spinny:~/writing $ vim hono-framework-guide.md
1~2सालों तक JavaScript वेब फ्रेमवर्क चुनने का मतलब था एक ट्रेड-ऑफ स्वीकार करना: Express यूनिवर्सल था पर धीमा और Node-बाउंड, Fastify तेज़ था पर सिर्फ Node के लिए, Next.js फुल-फ़ीचर्ड था पर भारी। जब एज रनटाइम — Cloudflare Workers, Deno Deploy, Bun, Vercel Edge — आए, इन फ्रेमवर्क्स की सीमाएं उजागर हुईं: इनकंपैटिबल डिपेंडेंसीज़, बड़े बंडल, Node के `req`/`res` से बंधे APIs।3~4[Hono](https://hono.dev) (जापानी में "ज्वाला" 🔥) इसका आधुनिक उत्तर है। 14KB से कम का फ्रेमवर्क, पूरी तरह वेब स्टैंडर्ड्स (`Request`, `Response`, `fetch`) पर बना, जो हर JavaScript रनटाइम पर चलता है। एक ही कोड Cloudflare Workers, Bun, Deno, Node.js, Vercel, Netlify और AWS Lambda पर बिना बदलाव के डिप्लॉय होता है।5~6## Hono क्यों7~8Hono तीन चीज़ें सबसे बेहतर करता है:9~101. **परफॉर्मेंस।** `RegExpRouter` सभी रूट पैटर्न्स को एक regex में कंपाइल करता है, ट्रेडिशनल राउटर्स के लीनियर लूप से बचता है। बेंचमार्क 4 लाख ops/s से ऊपर हैं।112. **पोर्टेबिलिटी।** वेब स्टैंडर्ड्स यानी ज़ीरो Node डिपेंडेंसी। एक ही `app.fetch` Cloudflare Worker में default export, `Bun.serve` को पास, Deno सर्वर पर माउंट या `@hono/node-server` से अडॉप्ट होता है।123. **TypeScript-first DX।** लिटरल टाइप के रूप में अनुमानित पाथ पैरामीटर्स, एंड-टू-एंड टाइप-सेफ RPC क्लाइंट, इनपुट और आउटपुट टाइप अनुमानित करने वाले वैलिडेटर्स।13~14```mermaid15graph LR16 Client[Client] -->|Request| App[app.fetch]17 App --> MW1[Middleware 1]18 MW1 --> MW2[Middleware 2]19 MW2 --> Router[RegExpRouter]20 Router --> Handler[Route Handler]21 Handler --> Context[c.json / c.text]22 Context -->|Response| Client23 App -.->|deploy| CF[Cloudflare Workers]24 App -.->|deploy| Bun[Bun]25 App -.->|deploy| Deno[Deno]26 App -.->|deploy| Node[Node.js]27 App -.->|deploy| Vercel[Vercel]28```29~30## शुरुआत31~32सबसे तेज़ रास्ता ऑफिशियल स्टार्टर है, जो आपके चुने रनटाइम के लिए प्रोजेक्ट स्कैफोल्ड करता है।33~34```bash35npm create hono@latest my-api36cd my-api37npm install38npm run dev39```40~41स्टार्टर पूछता है कौन सा टेम्पलेट: `cloudflare-workers`, `bun`, `deno`, `nodejs`, `vercel`, `aws-lambda`, `nextjs` और भी। तुरंत आज़माने के लिए एक फाइल से भी शुरू कर सकते हैं:42~43```typescript44// src/index.ts45import { Hono } from 'hono'46~47const app = new Hono()48~49app.get('/', (c) => c.text('Hello Hono!'))50~51export default app52```53~54Cloudflare Workers पर इतना काफी है। Bun पर: `Bun.serve({ fetch: app.fetch, port: 3000 })`। Node पर: `@hono/node-server` से `serve({ fetch: app.fetch })`।55~56## रूटिंग57~58रूट्स HTTP वर्ब मेथड्स से डिक्लेयर होते हैं और पैरामीटर्स, वाइल्डकार्ड्स, regex को सपोर्ट करते हैं।59~60```typescript61import { Hono } from 'hono'62~63const app = new Hono()64~65app.get('/', (c) => c.text('Home'))66app.get('/posts/:id', (c) => {67 const id = c.req.param('id') // string, टाइप्ड68 return c.json({ id })69})70app.get('/posts/:id/comments/:commentId', (c) => {71 const { id, commentId } = c.req.param()72 return c.json({ id, commentId })73})74app.get('/files/*', (c) => c.text('Wildcard'))75app.post('/posts', async (c) => {76 const body = await c.req.json()77 return c.json({ created: body }, 201)78})79```80~81पैरामीटर्स लिटरल टाइप के रूप में अनुमानित होते हैं: TypeScript जानता है कि `c.req.param('id')` तभी `string` लौटाता है जब आपने पैटर्न में `:id` डिक्लेयर किया हो। नाम गलत होना कंपाइल-टाइम एरर है।82~83### रूट्स को ग्रुप करना84~85`app.route()` सब-एप्लिकेशन्स को मॉड्यूल की तरह कंपोज़ करने देता है, हर एक का अपना प्रिफ़िक्स।86~87```typescript88// routes/posts.ts89import { Hono } from 'hono'90~91const posts = new Hono()92posts.get('/', (c) => c.json({ posts: [] }))93posts.get('/:id', (c) => c.json({ id: c.req.param('id') }))94export default posts95~96// src/index.ts97import { Hono } from 'hono'98import posts from './routes/posts'99~100const app = new Hono()101app.route('/posts', posts)102```103~104नेस्टेड रूट्स रूट ऐप का बेस पाथ और टाइप विरासत में लेते हैं, इसलिए RPC क्लाइंट पूरी संरचना देखता है।105~106## Context ऑब्जेक्ट107~108हर हैंडलर को एक `c` मिलता है — मौजूदा रिक्वेस्ट का Context। इनपुट पढ़ने और आउटपुट प्रोड्यूस करने के लिए सीखने वाला यही एक API है।109~110```typescript111app.post('/echo', async (c) => {112 // पढ़ना113 const userAgent = c.req.header('User-Agent')114 const page = c.req.query('page')115 const body = await c.req.json()116 const env = c.env // बाइंडिंग्स (Cloudflare पर KV, D1, secrets)117~118 // मिडलवेयर और हैंडलर के बीच साझा वेरिएबल्स119 c.set('requestId', crypto.randomUUID())120 const id = c.get('requestId')121~122 // रेस्पॉन्स123 c.header('X-Request-Id', id)124 c.status(200)125 return c.json({ userAgent, page, body, id })126})127```128~129मुख्य रेस्पॉन्स मेथड्स: `c.text`, `c.json`, `c.html`, `c.body` (raw), `c.redirect`। सभी दूसरे आर्ग्युमेंट के रूप में स्टेटस कोड लेते हैं।130~131## मिडलवेयर: अनियन मॉडल132~133मिडलवेयर `(c, next) => ...` फंक्शन्स हैं जो हैंडलर के पहले और बाद में कोड चला सकते हैं। कंपोज़ होने पर ये क्लासिक अनियन मॉडल बनाते हैं: पहले रजिस्टर हुआ मिडलवेयर पहले शुरू और आखिर में खत्म होता है।134~135```typescript136import { Hono } from 'hono'137import { logger } from 'hono/logger'138import { cors } from 'hono/cors'139import { secureHeaders } from 'hono/secure-headers'140~141const app = new Hono()142~143app.use('*', logger())144app.use('*', secureHeaders())145app.use('/api/*', cors({ origin: 'https://spinny.dev' }))146~147app.use('*', async (c, next) => {148 const start = performance.now()149 await next()150 c.header('X-Response-Time', `${performance.now() - start}ms`)151})152```153~154`await next()` कंट्रोल अगले मिडलवेयर को देता है। उसके बाद का सब रेस्पॉन्स फेज़ में चलता है। `next()` से पहले `Response` लौटाने पर चेन शॉर्ट-सर्किट हो जाती है।155~156### बिल्ट-इन मिडलवेयर157~158| मिडलवेयर | काम |159|-----------|---------|160| `logger` | मेथड, पाथ, स्टेटस, ड्यूरेशन का स्ट्रक्चर्ड लॉग |161| `cors` | origin, मेथड्स, हेडर्स से कॉन्फ़िगर करने योग्य CORS |162| `csrf` | origin-आधारित CSRF प्रोटेक्शन |163| `secureHeaders` | CSP, HSTS, X-Frame-Options सेट करता है |164| `bearerAuth` / `basicAuth` | आउट-ऑफ़-द-बॉक्स Bearer/Basic auth |165| `jwt` | `jose` से JWT वेरिफ़ाई/साइन |166| `etag` | ETag जेनरेट करता है, 304 हैंडल करता है |167| `cache` | Web Cache API कैशिंग |168| `compress` | रेस्पॉन्स पर gzip/deflate |169| `bodyLimit` | थ्रेशोल्ड से ऊपर के बॉडी रिजेक्ट |170| `timing` | प्रोफाइलिंग के लिए Server-Timing हेडर |171~172### टाइप-सेफ कस्टम मिडलवेयर173~174```typescript175import { createMiddleware } from 'hono/factory'176~177type AuthVars = { userId: string; role: 'user' | 'admin' }178~179export const requireAuth = createMiddleware<{ Variables: AuthVars }>(180 async (c, next) => {181 const token = c.req.header('Authorization')?.replace('Bearer ', '')182 if (!token) return c.json({ error: 'Unauthorized' }, 401)183~184 const payload = await verifyJwt(token)185 c.set('userId', payload.sub)186 c.set('role', payload.role)187 await next()188 }189)190~191app.get('/me', requireAuth, (c) => {192 const userId = c.var.userId // string, टाइप्ड193 return c.json({ userId })194})195```196~197## Zod से वैलिडेशन198~199```typescript200import { Hono } from 'hono'201import { zValidator } from '@hono/zod-validator'202import { z } from 'zod'203~204const createPost = z.object({205 title: z.string().min(1).max(200),206 body: z.string().min(1),207 tags: z.array(z.string()).default([]),208})209~210app.post(211 '/posts',212 zValidator('json', createPost),213 (c) => {214 const data = c.req.valid('json')215 return c.json({ ok: true, post: data }, 201)216 }217)218```219~220अगर बॉडी वैलिडेट नहीं होती, Hono हैंडलर बुलाने से पहले Zod एरर के साथ 400 लौटाता है। `query`, `param`, `header`, `cookie`, `form` भी वैलिडेट कर सकते हैं।221~222## RPC: एंड-टू-एंड टाइप-सेफ क्लाइंट223~224```typescript225// server.ts226import { Hono } from 'hono'227import { zValidator } from '@hono/zod-validator'228import { z } from 'zod'229~230const app = new Hono()231 .get('/posts/:id', (c) =>232 c.json({ id: c.req.param('id'), title: 'Hello' })233 )234 .post(235 '/posts',236 zValidator('json', z.object({ title: z.string(), body: z.string() })),237 (c) => c.json({ ok: true }, 201)238 )239~240export type AppType = typeof app241export default app242```243~244```typescript245// client.ts246import { hc } from 'hono/client'247import type { AppType } from './server'248~249const client = hc<AppType>('https://api.spinny.dev')250~251const res = await client.posts[':id'].$get({ param: { id: '42' } })252if (res.ok) {253 const data = await res.json()254 console.log(data.title)255}256~257const created = await client.posts.$post({258 json: { title: 'नमस्ते', body: 'Hono एक ज्वाला है' },259})260```261~262सर्वर पर रूट का नाम बदलें और CI में क्लाइंट का TypeScript तुरंत टूट जाता है। tRPC जैसा फायदा, पर स्टैंडर्ड HTTP पर, बिना खास मिडलवेयर के, छोटे बंडल के साथ।263~264### स्टेटस कोड डिस्क्रिमिनेशन265~266```typescript267.get('/posts/:id', (c) => {268 const post = findPost(c.req.param('id'))269 if (!post) return c.json({ error: 'not found' }, 404)270 return c.json({ post }, 200)271})272```273~274```typescript275const res = await client.posts[':id'].$get({ param: { id } })276if (res.status === 404) {277 const { error } = await res.json() // { error: string }278}279if (res.status === 200) {280 const { post } = await res.json() // { post: Post }281}282```283~284## राउटर्स और परफॉर्मेंस285~286| राउटर | खूबियाँ | कब इस्तेमाल करें |287|--------|-----------|-------------|288| `RegExpRouter` | अधिकतम स्पीड, कंपाइल्ड regex | अधिकांश APIs के लिए डिफ़ॉल्ट |289| `TrieRouter` | हर पैटर्न सपोर्ट | जटिल पैटर्न जो RegExp हैंडल नहीं करता |290| `SmartRouter` | सबसे अच्छा ऑटो चुनता है | अनुशंसित डिफ़ॉल्ट |291| `LinearRouter` | अल्ट्रा-फास्ट रजिस्ट्रेशन | वन-शॉट वर्कर्स, क्रिटिकल कोल्ड स्टार्ट |292| `PatternRouter` | न्यूनतम बंडल (<15KB) | अत्यधिक साइज़ बाध्यताएं |293~294```typescript295import { Hono } from 'hono'296import { LinearRouter } from 'hono/router/linear-router'297~298const app = new Hono({ router: new LinearRouter() })299```300~301## मल्टी-रनटाइम डिप्लॉयमेंट302~303### Cloudflare Workers304~305```typescript306import { Hono } from 'hono'307~308type Bindings = { MY_KV: KVNamespace; DB: D1Database }309const app = new Hono<{ Bindings: Bindings }>()310~311app.get('/cache/:key', async (c) => {312 const value = await c.env.MY_KV.get(c.req.param('key'))313 return c.json({ value })314})315~316export default app317```318~319डिप्लॉय: `npx wrangler deploy`।320~321### Bun322~323```typescript324import { Hono } from 'hono'325const app = new Hono()326app.get('/', (c) => c.text('Bun + Hono'))327~328Bun.serve({ fetch: app.fetch, port: 3000 })329```330~331### Node.js332~333```typescript334import { serve } from '@hono/node-server'335import { Hono } from 'hono'336~337const app = new Hono()338app.get('/', (c) => c.text('Node + Hono'))339~340serve({ fetch: app.fetch, port: 3000 })341```342~343### Deno344~345```typescript346import { Hono } from 'jsr:@hono/hono'347const app = new Hono()348app.get('/', (c) => c.text('Deno + Hono'))349Deno.serve(app.fetch)350```351~352### Vercel353~354```typescript355// api/[[...route]].ts356import { Hono } from 'hono'357import { handle } from 'hono/vercel'358~359const app = new Hono().basePath('/api')360app.get('/hello', (c) => c.json({ msg: 'Hello from Vercel' }))361~362export const GET = handle(app)363export const POST = handle(app)364```365~366वही बिज़नेस कोड, वही रूटिंग, वही मिडलवेयर। सिर्फ अडैप्टर बदलता है।367~368## व्यावहारिक उदाहरण: ऑथ और DB के साथ REST API369~370```typescript371import { Hono } from 'hono'372import { jwt } from 'hono/jwt'373import { logger } from 'hono/logger'374import { cors } from 'hono/cors'375import { zValidator } from '@hono/zod-validator'376import { z } from 'zod'377~378type Bindings = { DB: D1Database; JWT_SECRET: string }379type Variables = { jwtPayload: { sub: string } }380~381const app = new Hono<{ Bindings: Bindings; Variables: Variables }>()382~383app.use('*', logger())384app.use('/api/*', cors({ origin: 'https://spinny.dev', credentials: true }))385~386const auth = (c: any, next: any) =>387 jwt({ secret: c.env.JWT_SECRET })(c, next)388~389const api = app.basePath('/api')390~391api.get('/posts', async (c) => {392 const { results } = await c.env.DB393 .prepare('SELECT id, title, created_at FROM posts ORDER BY created_at DESC LIMIT 50')394 .all()395 return c.json({ posts: results })396})397~398api.post(399 '/posts',400 auth,401 zValidator('json', z.object({402 title: z.string().min(1).max(200),403 body: z.string().min(1),404 })),405 async (c) => {406 const { title, body } = c.req.valid('json')407 const userId = c.var.jwtPayload.sub408 const result = await c.env.DB409 .prepare('INSERT INTO posts (title, body, author_id) VALUES (?, ?, ?) RETURNING id')410 .bind(title, body, userId)411 .first<{ id: number }>()412 return c.json({ id: result?.id }, 201)413 }414)415~416api.onError((err, c) => {417 console.error(err)418 return c.json({ error: 'Internal error' }, 500)419})420~421export type AppType = typeof api422export default app423```424~425React क्लाइंट इसे पूर्ण टाइप सेफ्टी के साथ कंज़्यूम करता है:426~427```typescript428import { hc } from 'hono/client'429import type { AppType } from '../api/src/index'430~431const api = hc<AppType>(import.meta.env.VITE_API_URL)432~433const res = await api.posts.$post({434 json: { title: '2026 में Hono', body: '...' },435}, {436 headers: { Authorization: `Bearer ${token}` },437})438```439~440## टेस्टिंग441~442```typescript443import { describe, it, expect } from 'vitest'444import app from '../src/index'445~446describe('GET /api/posts', () => {447 it('पोस्ट्स की सूची लौटाता है', async () => {448 const res = await app.request('/api/posts')449 expect(res.status).toBe(200)450 const body = await res.json()451 expect(body.posts).toBeInstanceOf(Array)452 })453})454```455~456`app.request()` बिना HTTP सर्वर के रूट्स टेस्ट करने देता है।457~458## बेस्ट प्रैक्टिसेज़459~460### 1. रूट डेफिनिशन्स को चेन करें461~462```typescript463const app = new Hono()464 .get('/posts', handler1)465 .post('/posts', handler2)466 .get('/posts/:id', handler3)467```468~469चेनिंग RPC क्लाइंट के लिए जरूरी है। अलग लाइनों पर `app.get(...)` अनुमान तोड़ देता है।470~471### 2. इम्प्लीमेंटेशन नहीं, टाइप एक्सपोर्ट करें472~473क्लाइंट को `AppType` import करना चाहिए। `import type` फ्रंटएंड बिल्ड में बैकएंड कोड शामिल नहीं करता।474~475### 3. हर डोमेन पर एक राउटर476~477`posts`, `users`, `webhooks` के लिए अलग सब-ऐप। `app.route()` से कंपोज़ करें।478~479### 4. हमेशा बॉर्डर पर वैलिडेट करें480~481हर एक्सटर्नल इनपुट `zValidator` से होकर जाए।482~483### 5. ग्लोबल क्लाइंट्स पर नहीं, बाइंडिंग्स पर निर्भर करें484~485Cloudflare पर `c.env` से KV/D1/R2 तक पहुंचें।486~487### 6. राउटर ऑप्टिमाइज़ करने से पहले मापें488~489डिफ़ॉल्ट `SmartRouter` 95% मामलों के लिए ठीक है।490~491## निष्कर्ष492~493Hono 2026 में TypeScript में एज-रेडी APIs बनाने का दे फ़ैक्टो स्टैंडर्ड बन गया है। वेब स्टैंडर्ड्स, परफॉर्मेंस, टाइप सेफ्टी और पोर्टेबिलिटी का संयोजन ट्रेडिशनल फ्रेमवर्क्स को रोकने वाली ठीक उन समस्याओं को हल करता है।494~495> **शुरुआती चेकलिस्ट:**496>497> - [x] `npm create hono@latest` और रनटाइम टेम्पलेट चुनें498> - [x] चेनिंग से रूट्स डिफ़ाइन करें (`.get(...).post(...)`)499> - [x] `logger`, `cors`, `secureHeaders` ग्लोबल मिडलवेयर के रूप में जोड़ें500> - [x] हर इनपुट `@hono/zod-validator` से वैलिडेट करें501> - [x] `AppType` एक्सपोर्ट करें और टाइप-सेफ `hc` क्लाइंट से API कंज़्यूम करें502> - [x] `app.request()` से टेस्ट लिखें — HTTP सर्वर की जरूरत नहीं503> - [x] `wrangler deploy` (CF), `vercel deploy` या आपके रनटाइम के बंडलर से डिप्लॉय करें504~
NORMAL · hono-framework-guide.md [readonly]504 lines · :q to close