[G1-Sync] Manual knowledge update

This commit is contained in:
Antigravity Agent
2026-05-10 22:08:15 +09:00
parent 21ac3ed255
commit 504fd5fb42
3011 changed files with 380280 additions and 206977 deletions
@@ -0,0 +1,414 @@
---
id: backend-hono-middleware-deep
title: Hono Middleware — modern Express alternative
category: Coding
status: draft
source_trust_level: B
verification_status: conceptual
created_at: 2026-05-09
updated_at: 2026-05-09
tags: [backend, hono, vibe-coding]
tech_stack: { language: "TS", applicable_to: ["Backend"] }
applied_in: []
aliases: [Hono, middleware, Cloudflare Workers, Deno, Bun, edge-friendly]
---
# Hono Middleware Deep
> Modern Express alternative. **Edge-friendly (CF Workers / Deno / Bun / Node), TypeScript-first, 작은 bundle**.
## 📖 핵심 개념
- Web standards (Fetch, Request, Response).
- 매 runtime (Node / Bun / Deno / CF / Lambda).
- Type-safe routing.
- Built-in middleware.
## 💻 코드 패턴
### Basic
```ts
import { Hono } from 'hono';
const app = new Hono();
app.get('/', (c) => c.text('Hello'));
app.get('/users/:id', (c) => c.json({ id: c.req.param('id') }));
// Cloudflare Worker
export default app;
// Bun
Bun.serve({ fetch: app.fetch });
// Node
import { serve } from '@hono/node-server';
serve(app);
```
→ 같은 code, 다른 runtime.
### Built-in middleware
```ts
import { logger } from 'hono/logger';
import { cors } from 'hono/cors';
import { secureHeaders } from 'hono/secure-headers';
import { compress } from 'hono/compress';
import { etag } from 'hono/etag';
import { jwt } from 'hono/jwt';
app.use(logger());
app.use(cors({ origin: 'https://app.example.com' }));
app.use(secureHeaders());
app.use(compress());
app.use(etag());
app.use('/api/*', jwt({ secret: 'secret' }));
```
→ 모든 production middleware.
### Custom middleware
```ts
const auth = async (c, next) => {
const token = c.req.header('Authorization')?.replace('Bearer ', '');
if (!token) return c.text('Unauthorized', 401);
const user = await verifyToken(token);
if (!user) return c.text('Invalid', 401);
c.set('user', user);
await next();
};
app.use('/api/*', auth);
app.get('/api/me', (c) => {
const user = c.get('user');
return c.json(user);
});
```
### Type-safe context
```ts
type Variables = {
user: User;
};
const app = new Hono<{ Variables: Variables }>();
app.use('*', async (c, next) => {
c.set('user', { id: '1' });
await next();
});
app.get('/', (c) => {
const user = c.get('user'); // type: User
return c.json(user);
});
```
### Validator
```ts
import { zValidator } from '@hono/zod-validator';
import { z } from 'zod';
app.post(
'/users',
zValidator('json', z.object({ name: z.string(), email: z.string().email() })),
(c) => {
const data = c.req.valid('json');
// type-safe
return c.json({ id: '...', ...data });
}
);
```
### RPC mode (type-safe client)
```ts
// Server
const route = app.post('/users', zValidator('json', userSchema), (c) => {
return c.json({ id: '...' });
});
export type AppType = typeof route;
// Client
import { hc } from 'hono/client';
import type { AppType } from './server';
const client = hc<AppType>('https://api.example.com');
const r = await client.users.$post({ json: { name: 'Alice', email: 'a@x' } });
const data = await r.json(); // type-safe
```
→ tRPC 식 type-safe RPC.
### Streaming
```ts
import { stream, streamSSE } from 'hono/streaming';
app.get('/stream', (c) => {
return stream(c, async (stream) => {
for (let i = 0; i < 100; i++) {
await stream.writeln(`chunk ${i}`);
await stream.sleep(100);
}
});
});
app.get('/sse', (c) => {
return streamSSE(c, async (stream) => {
let id = 0;
while (true) {
await stream.writeSSE({ event: 'msg', data: 'hello', id: String(id++) });
await stream.sleep(1000);
}
});
});
```
### WebSocket (Bun / Deno)
```ts
import { upgradeWebSocket } from 'hono/cloudflare-workers';
app.get(
'/ws',
upgradeWebSocket((c) => ({
onMessage: (event, ws) => ws.send(`echo: ${event.data}`),
onClose: () => console.log('closed'),
}))
);
```
### Sub-app (modular)
```ts
const userApp = new Hono();
userApp.get('/', (c) => c.json([]));
userApp.get('/:id', (c) => c.json({ id: c.req.param('id') }));
const orderApp = new Hono();
orderApp.get('/', (c) => c.json([]));
const app = new Hono();
app.route('/users', userApp);
app.route('/orders', orderApp);
```
→ Module 별 분리.
### Error handling
```ts
app.onError((err, c) => {
console.error(err);
return c.json({ error: err.message }, 500);
});
app.notFound((c) => c.text('Not found', 404));
```
### File serving
```ts
import { serveStatic } from '@hono/node-server/serve-static';
app.use('/static/*', serveStatic({ root: './public' }));
```
### OpenAPI integration
```ts
import { OpenAPIHono, createRoute, z } from '@hono/zod-openapi';
const app = new OpenAPIHono();
const route = createRoute({
method: 'get',
path: '/users/:id',
request: { params: z.object({ id: z.string() }) },
responses: {
200: { content: { 'application/json': { schema: z.object({ id: z.string() }) } } },
},
});
app.openapi(route, (c) => c.json({ id: c.req.valid('param').id }));
app.doc('/openapi.json', { openapi: '3.0.0', info: { title: 'API', version: '1.0' } });
```
→ Zod schema → OpenAPI auto.
### Performance
```
Hono: ~30k req/sec on Bun.
Express: ~10k req/sec on Node.
Fastify: ~25k.
→ Hono 가 가장 빠름 + 작은.
```
### Bundle size
```
Hono: ~12 KB.
Express: ~80 KB.
Fastify: ~90 KB.
→ Edge / serverless 친화.
```
### Use case
```
- Cloudflare Worker.
- Vercel Edge.
- Bun server.
- Deno server.
- Node 서버 (alternative to Express).
- Lambda.
```
### Production deploy
```bash
# Cloudflare
wrangler deploy
# Vercel
vercel --prod
# Bun
bun run server.ts
# Node
node server.js
```
### vs Express
```
Express:
- 가장 mature.
- 큰 ecosystem.
- Node only.
Hono:
- Modern, edge-friendly.
- Type-safe.
- Multi-runtime.
- 작은 ecosystem (자라는).
→ New project = Hono.
Existing Express = stay.
```
### vs Fastify
```
Fastify:
- Node-first.
- Plugin system.
- 빠름.
Hono:
- Edge-first.
- Web standards.
- 더 작은.
→ Edge / serverless = Hono.
Node-only enterprise = Fastify.
```
### Middleware order
```ts
app.use(logger()); // 1st
app.use(cors());
app.use(jwt({ secret })); // auth
app.use('/api/*', rateLimit); // rate
app.get('/api/users', ...); // route
```
→ Order matters.
### Context (c)
```ts
c.req.url // string
c.req.method
c.req.header('...')
c.req.query('...')
c.req.param('...')
c.req.json() // Promise<json>
c.req.formData()
c.req.text()
c.json({}) // Response
c.text('hi')
c.html('<p>hi</p>')
c.redirect('/path')
c.status(404)
c.set('key', val)
c.get('key')
c.env // Cloudflare Worker env
```
### Auth patterns
```ts
// JWT
app.use('/api/*', jwt({ secret: c.env.JWT_SECRET }));
// Custom
const apiKey = c.req.header('X-API-Key');
if (apiKey !== c.env.API_KEY) return c.text('Unauthorized', 401);
// Basic auth
import { basicAuth } from 'hono/basic-auth';
app.use('/admin/*', basicAuth({ username: 'admin', password: 'secret' }));
```
### Rate limit
```ts
const rateLimiter = new Map<string, { count: number; reset: number }>();
app.use('/api/*', async (c, next) => {
const ip = c.req.header('x-real-ip') ?? 'unknown';
const now = Date.now();
const limit = rateLimiter.get(ip) ?? { count: 0, reset: now + 60000 };
if (now > limit.reset) { limit.count = 0; limit.reset = now + 60000; }
limit.count++;
rateLimiter.set(ip, limit);
if (limit.count > 100) return c.text('Rate limit', 429);
await next();
});
```
→ Cloudflare = built-in. Self-host = manual.
### Real-world
- **Cloudflare**: Hono 의 큰 user.
- **Vercel**: Edge functions.
- **Several startups**: edge-first.
## 🤔 의사결정 기준
| 상황 | 추천 |
|---|---|
| Edge / Cloudflare | Hono |
| Node 새 project | Hono |
| Existing Express | Stay or migrate gradual |
| Type-safe RPC | Hono RPC mode |
| OpenAPI | Hono + zod-openapi |
| WebSocket | Hono (Bun/Deno) |
## ❌ 안티패턴
- **모든 거 1 file**: sub-app 사용.
- **No type-safe**: zValidator.
- **No error handler**: ugly.
- **Middleware order 잘못**: auth before logger.
- **Big bundle**: edge limit.
## 🤖 LLM 활용 힌트
- Hono = modern Express.
- Multi-runtime (CF / Node / Bun / Deno).
- Type-safe RPC + OpenAPI.
- 작은 bundle (edge 친화).
## 🔗 관련 문서
- [[Backend_Hono_Modern]]
- [[Backend_Edge_Runtime_Deep]]
- [[Backend_Edge_Functions]]