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
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
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
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.