Lewati ke konten utama
menjadi.dev
Chapter 17.6 Database Menengah

Hono: Middleware dan Validasi

Tingkatkan aplikasi dengan middleware chain dan input validation

Tujuan Pembelajaran

  • Bisa membuat dan menggunakan middleware
  • Mengerti middleware chain dan next()
  • Mengintegrasikan Zod untuk validasi

Analogi

Diagram

      Middleware Chain:
Request → Logger → Auth → Validator → Handler → Response

Setiap middleware bisa:
- Modify request/response
- Stop chain (tidak panggil next)
- Execute code before dan after handler
    

Middleware pattern di Hono memungkinkan reusable logic untuk cross-cutting concerns

Penjelasan Konsep

Middleware adalah kunci untuk membangun backend yang terstruktur. Bayangkan middleware sebagai ‘lapisan keamanan’ di bandara: setiap penumpang melewati beberapa checkpoint sebelum sampai ke gate. Setiap checkpoint bisa mengizinkan, memodifikasi, atau menolak.

Middleware di Hono

Di Hono, middleware adalah fungsi yang menerima context dan next function. Middleware bisa berjalan sebelum handler (panggil next()), setelah handler (kode setelah next()), atau menggantikan handler sama sekali (tidak panggil next()).

app.use('*', async (c, next) => {
  console.log('Before handler');  // Sebelum handler
  await next();                  // Lanjut ke handler berikutnya
  console.log('After handler');   // Setelah handler selesai
});

Built-in Middleware Hono

Hono menyediakan banyak middleware bawaan:

  • logger: Request logging ke console
  • cors: Cross-origin resource sharing
  • csrf: CSRF protection
  • etag: HTTP ETag untuk caching
  • pretty-json: Format JSON yang readable
  • serveStatic: Serve static files
  • jwt: JWT authentication
  • zod-validator: Integrasi Zod validation

Validator Middleware dengan Zod

Hono punya integrasi Zod yang seamless untuk validasi input:

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

const userSchema = z.object({
  name: z.string().min(1),
  email: z.string().email(),
  age: z.number().min(0).max(150),
});

app.post('/users', zValidator('json', userSchema), (c) => {
  const data = c.req.valid('json'); // Sudah tervalidasi, typed!
  // ... simpan ke database
  return c.json({ success: true }, 201);
});

Notice: Setelah validasi, data sudah ter-typing sesuai schema Zod.

TypeScript akan tahu tipe data yang valid.

Auth Middleware

Contoh middleware autentikasi dengan JWT:

app.use('/api/*', async (c, next) => {
  const token = c.req.header('Authorization')?.replace('Bearer ', '');
  if (!token) return c.json({ error: 'Unauthorized' },

401);

  try {
    const payload = await verify(token, secret);
    c.set('user', payload); // Attach ke context
    await next();
  } catch {
    return c.json({ error: 'Invalid token' }, 403);
  }
});

Middleware ini berjalan untuk SEMUA route yang dimulai dengan /api/.

Kita menggunakan c.set() untuk menyimpan data user ke context, sehingga handler bisa mengaksesnya dengan c.get(‘user’).

Contoh Kode

typescript
import { Hono } from 'hono';
import { logger } from 'hono/logger';
import { cors } from 'hono/cors';
import { zValidator } from '@hono/zod-validator';
import { z } from 'zod';
import { jwt } from 'hono/jwt';

const app = new Hono();

// Global middleware
app.use(logger());
app.use(cors({ origin: 'http://localhost:5173' }));

// Validation schemas
const createUserSchema = z.object({
  name: z.string().min(2, 'Nama minimal 2 karakter'),
  email: z.string().email('Email tidak valid'),
  role: z.enum(['user', 'admin']).default('user'),
});

// Public routes
app.get('/health', (c) => c.json({ status: 'ok', timestamp: new Date().toISOString() }));

app.post('/login', async (c) => {
  const { email, password } = await c.req.json();
  // ... verify credentials
  const token = await sign({ email }, secret);
  return c.json({ token });
});

// Protected routes
app.use('/api/*', jwt({ secret: 'my-secret' }));

app.get('/api/users', (c) => {
  const user = c.get('jwtPayload');
  return c.json({ users: [], requestedBy: user.email });
});

app.post('/api/users',
  zValidator('json', createUserSchema),
  (c) => {
    const data = c.req.valid('json'); // Typed sebagai z.infer<typeof createUserSchema>
    console.log('Creating user:', data);
    return c.json({ id: '123', ...data }, 201);
  }
);

// Error handling
app.onError((err, c) => {
  console.error(err);
  return c.json({ error: 'Internal Server Error' }, 500);
});

export default app;

Penjelasan Kode

Middleware dideklarasikan dengan app.use(). Urutan penting — middleware dieksekusi sesuai urutan deklarasi. zValidator otomatis return 400 dengan error detail kalau validasi gagal.

Prompt AI

Buat middleware rate limiting menggunakan memory store (Map). Limit 100 request per 15 menit per IP.

Pertanyaan Reflektif

Coba buat middleware kompresi response. Gunakan CompressionStream API untuk gzip response body.