Bỏ qua

Middleware Patterns

Middleware Concept

Request Pipeline

┌─────────────────────────────────────────────────────────────┐
│                   MIDDLEWARE PIPELINE                        │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│  Request                                                     │
│     │                                                        │
│     ▼                                                        │
│  ┌─────────────┐                                            │
│  │   CORS      │  ──▶ Add CORS headers                      │
│  └─────────────┘                                            │
│     │                                                        │
│     ▼                                                        │
│  ┌─────────────┐                                            │
│  │   Auth      │  ──▶ Verify JWT                            │
│  └─────────────┘                                            │
│     │                                                        │
│     ▼                                                        │
│  ┌─────────────┐                                            │
│  │  Logging    │  ──▶ Log request                           │
│  └─────────────┘                                            │
│     │                                                        │
│     ▼                                                        │
│  ┌─────────────┐                                            │
│  │  Handler    │  ──▶ Process request                       │
│  └─────────────┘                                            │
│     │                                                        │
│     ▼                                                        │
│  Response                                                    │
│                                                              │
└─────────────────────────────────────────────────────────────┘

Manual Middleware

Simple Implementation

type Middleware = (
  request: Request,
  env: Env,
  next: () => Promise<Response>
) => Promise<Response>;

// CORS Middleware
const cors: Middleware = async (request, env, next) => {
  // Handle preflight
  if (request.method === 'OPTIONS') {
    return new Response(null, {
      headers: {
        'Access-Control-Allow-Origin': '*',
        'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE',
        'Access-Control-Allow-Headers': 'Content-Type, Authorization',
      },
    });
  }

  // Continue to next middleware
  const response = await next();

  // Add CORS headers to response
  const newResponse = new Response(response.body, response);
  newResponse.headers.set('Access-Control-Allow-Origin', '*');

  return newResponse;
};

// Auth Middleware
const auth: Middleware = async (request, env, next) => {
  const authHeader = request.headers.get('Authorization');

  if (!authHeader?.startsWith('Bearer ')) {
    return Response.json({ error: 'Unauthorized' }, { status: 401 });
  }

  // Verify token...
  return next();
};

Chain Middlewares

function createHandler(middlewares: Middleware[], handler: Handler) {
  return async (request: Request, env: Env): Promise<Response> => {
    let index = 0;

    const next = async (): Promise<Response> => {
      if (index < middlewares.length) {
        const middleware = middlewares[index++];
        return middleware(request, env, next);
      }
      return handler(request, env);
    };

    return next();
  };
}

// Usage
const handler = createHandler(
  [cors, auth, logging],
  async (request, env) => {
    return Response.json({ data: 'protected' });
  }
);

Built-in Middleware

import { Hono } from 'hono';
import { cors } from 'hono/cors';
import { logger } from 'hono/logger';
import { jwt } from 'hono/jwt';
import { secureHeaders } from 'hono/secure-headers';

const app = new Hono();

// Global middleware
app.use('*', logger());
app.use('*', cors());
app.use('*', secureHeaders());

// Route-specific middleware
app.use('/api/*', jwt({ secret: 'my-secret' }));

app.get('/api/users', (c) => {
  const payload = c.get('jwtPayload');
  return c.json({ user: payload.sub });
});

export default app;

Custom Hono Middleware

import { Hono } from 'hono';
import { createMiddleware } from 'hono/factory';

interface Env {
  SUPABASE_URL: string;
  SUPABASE_ANON_KEY: string;
}

// Custom auth middleware
const supabaseAuth = createMiddleware<{ Bindings: Env }>(async (c, next) => {
  const authHeader = c.req.header('Authorization');

  if (!authHeader) {
    return c.json({ error: 'Missing authorization header' }, 401);
  }

  // Verify with Supabase
  const response = await fetch(`${c.env.SUPABASE_URL}/auth/v1/user`, {
    headers: { Authorization: authHeader },
  });

  if (!response.ok) {
    return c.json({ error: 'Invalid token' }, 401);
  }

  const user = await response.json();
  c.set('user', user);

  await next();
});

// Rate limiting middleware
const rateLimit = createMiddleware<{ Bindings: Env }>(async (c, next) => {
  const ip = c.req.header('CF-Connecting-IP') || 'unknown';
  const key = `rate:${ip}`;

  // Check rate limit in KV
  const count = parseInt(await c.env.MY_KV.get(key) || '0');

  if (count > 100) {
    return c.json({ error: 'Rate limit exceeded' }, 429);
  }

  // Increment count
  await c.env.MY_KV.put(key, (count + 1).toString(), { expirationTtl: 60 });

  await next();
});

const app = new Hono<{ Bindings: Env }>();

app.use('/api/*', rateLimit);
app.use('/api/*', supabaseAuth);

app.get('/api/me', (c) => {
  const user = c.get('user');
  return c.json(user);
});

Common Middleware Patterns

CORS

import { cors } from 'hono/cors';

app.use('/api/*', cors({
  origin: ['https://myapp.com', 'http://localhost:3000'],
  allowMethods: ['GET', 'POST', 'PUT', 'DELETE'],
  allowHeaders: ['Content-Type', 'Authorization'],
  credentials: true,
  maxAge: 86400,
}));

Error Handling

import { HTTPException } from 'hono/http-exception';

// Error handler middleware
app.onError((err, c) => {
  console.error('Error:', err);

  if (err instanceof HTTPException) {
    return c.json({ error: err.message }, err.status);
  }

  return c.json({ error: 'Internal Server Error' }, 500);
});

// Usage
app.get('/api/users/:id', async (c) => {
  const user = await findUser(c.req.param('id'));

  if (!user) {
    throw new HTTPException(404, { message: 'User not found' });
  }

  return c.json(user);
});

Request Validation

import { zValidator } from '@hono/zod-validator';
import { z } from 'zod';

const createUserSchema = z.object({
  email: z.string().email(),
  name: z.string().min(2),
  password: z.string().min(8),
});

app.post(
  '/api/users',
  zValidator('json', createUserSchema),
  async (c) => {
    const data = c.req.valid('json');
    // data is typed and validated
    return c.json({ created: true });
  }
);

Timing Middleware

const timing = createMiddleware(async (c, next) => {
  const start = Date.now();

  await next();

  const duration = Date.now() - start;
  c.res.headers.set('X-Response-Time', `${duration}ms`);

  console.log(`${c.req.method} ${c.req.path} - ${duration}ms`);
});

app.use('*', timing);

Middleware Order

Execution Order Matters

const app = new Hono();

// Order of middleware matters!
// 1. Logger first (logs all requests)
app.use('*', logger());

// 2. CORS (handles preflight)
app.use('*', cors());

// 3. Rate limiting
app.use('/api/*', rateLimit);

// 4. Authentication
app.use('/api/*', auth);

// 5. Routes
app.get('/api/data', handler);

// Error handler last
app.onError(errorHandler);

Tổng kết

Common Middleware

Middleware Purpose
CORS Cross-origin requests
Auth JWT/token validation
Logger Request logging
Rate Limit Prevent abuse
Validation Input validation
Error Handler Consistent errors

Best Practices

✅ Use Hono for cleaner middleware
✅ Order middleware carefully
✅ Handle errors globally
✅ Validate inputs early
✅ Add timing for monitoring

Q&A

  1. Middleware nào cần thiết nhất?
  2. Dùng Hono hay manual?
  3. Questions về patterns?