Hono: Router, Grouping, dan Error Handling
Struktur aplikasi backend yang terorganisir dan scalable
Tujuan Pembelajaran
- Bisa menggunakan Hono router
- Mengerti route grouping dan modularisasi
- Menguasai error handling dan custom responses
Analogi
App Structure:
src/
├── index.ts # Entry point + middleware global
├── routes/
│ ├── users.ts # User routes
│ └── posts.ts # Post routes
├── middleware/
│ ├── auth.ts # Auth middleware
│ └── validate.ts
└── types.ts # Shared types
Modularisasi route membuat aplikasi mudah dikelola saat bertumbuh
Penjelasan Konsep
Seiring aplikasi bertumbuh, meletakkan semua route di satu file menjadi tidak praktis.
Hono menyediakan mekanisme untuk memecah aplikasi menjadi modul-modul yang terorganisir.
Hono Router
Hono punya sistem router yang powerful.
Selain route biasa, Hono support:
- Path parameters: /users/:id
- Wildcard: /users/*
- Regexp: /version/(\d+)
- Multiple methods: app.on(‘PURGE’, ‘/cache’, handler)
- Priority: Static routes dicek dulu, baru parameterized
Route Grouping
Kamu bisa membuat sub-router dan mount ke app utama:
const userRoutes = new Hono();
userRoutes.get('/',
GetAllUsers);
userRoutes.get('/:id', getUser);
userRoutes.post('/', createUser);
app.route('/users', userRoutes);
// Hasil: GET /users, GET /users/:id, POST /users
Base Path
Alternatif lain: gunakan basePath saat membuat Hono instance:
const app = new Hono().basePath('/api');
// Sekarang semua route diawali /api
Error Handling
Hono punya beberapa cara handle error:
- app.onError(): Global error handler untuk semua route
- try-catch di handler: Handle error per-route
- HTTPException: Throw error dengan status code spesifik
import { HTTPException } from 'hono/http-exception';
app.get('/users/:id', (c) => {
const id = c.req.param('id');
const user = db.findUser(id);
if (!user) {
throw new HTTPException(404, { message: 'User not found' });
}
return c.json(user);
});
app.onError((err, c) => {
if (err instanceof HTTPException) {
return c.json({ error: err.message }, err.status);
}
return c.json({ error: 'Internal error' },
500);
});
Custom Response Helpers
Buat helper untuk response konsisten:
// utils/response.ts
export function success<T>(c: Context, data: T, status = 200) {
return c.json({ success: true, data }, status);
}
export function error(c: Context, message: string, status = 400) {
return c.json({ success: false, error: message }, status);
}
// Penggunaan
app.get('/users', (c) => {
return success(c, users);
}); Contoh Kode
// Modular Hono app
import { Hono } from 'hono';
import { logger } from 'hono/logger';
import { HTTPException } from 'hono/http-exception';
// Types
interface User {
id: string;
name: string;
email: string;
}
// Mock database
const users: User[] = [
{ id: '1', name: 'Budi', email: 'budi@mail.com' },
{ id: '2', name: 'Ani', email: 'ani@mail.com' },
];
// Response helpers
const jsonOk = (c: any, data: any) => c.json({ success: true, data });
const jsonErr = (c: any, message: string, status = 400) =>
c.json({ success: false, error: message }, status);
// User routes
const usersRoute = new Hono();
usersRoute.get('/', (c) => jsonOk(c, users));
usersRoute.get('/:id', (c) => {
const id = c.req.param('id');
const user = users.find(u => u.id === id);
if (!user) throw new HTTPException(404, { message: 'User not found' });
return jsonOk(c, user);
});
usersRoute.post('/', async (c) => {
const body = await c.req.json<User>();
const newUser = { id: String(users.length + 1), ...body };
users.push(newUser);
return jsonOk(c, newUser, 201);
});
usersRoute.put('/:id', async (c) => {
const id = c.req.param('id');
const body = await c.req.json<Partial<User>>();
const idx = users.findIndex(u => u.id === id);
if (idx === -1) throw new HTTPException(404, { message: 'User not found' });
users[idx] = { ...users[idx], ...body };
return jsonOk(c, users[idx]);
});
usersRoute.delete('/:id', (c) => {
const id = c.req.param('id');
const idx = users.findIndex(u => u.id === id);
if (idx === -1) throw new HTTPException(404, { message: 'User not found' });
users.splice(idx, 1);
return c.body(null, 204);
});
// Main app
const app = new Hono();
app.use(logger());
app.route('/api/users', usersRoute);
app.onError((err, c) => {
if (err instanceof HTTPException) {
return jsonErr(c, err.message, err.status);
}
console.error(err);
return jsonErr(c, 'Internal Server Error', 500);
});
export default app;Penjelasan Kode
Prompt AI
Pecah aplikasimu menjadi beberapa route module: users.ts, posts.ts, comments.ts. Tambahkan auth middleware untuk routes yang protected.
Pertanyaan Reflektif
Refactor aplikasimu menggunakan pattern MVC atau layered architecture. Pisahkan controller logic dari route definitions.