Exceptions
GamanJS menyediakan composeException untuk menangani error yang terjadi saat proses request. Exception handler bisa didaftarkan secara global (semua route) atau per-route.
Membuat Exception Handler
Section titled “Membuat Exception Handler”import { composeException } from 'gaman/compose';
export default composeException((error, ctx) => { console.error(`[Error] ${ctx.path}:`, error.message);
return ctx.send({ error: error.message, path: ctx.path, }).error(); // 500});composeException menerima callback (error, ctx) => Response dan mengembalikan ExceptionHandler.
Global Exception Handler
Section titled “Global Exception Handler”Daftarkan di defineBootstrap via app.mount():
import { defineBootstrap } from 'gaman';import router from './router';import GlobalException from './modules/app/exceptions/GlobalException';
defineBootstrap(async (app) => { // Daftarkan global exception handler app.mount(GlobalException);
app.mount(router); app.mountServer({ http: 3431 });});Global exception handler menangkap semua error yang tidak di-handle oleh exception handler per-route.
Per-Route Exception Handler
Section titled “Per-Route Exception Handler”Override error handling untuk route spesifik:
import { composeRouter, composeException } from 'gaman/compose';import PaymentController from './modules/app/controllers/PaymentController';
const PaymentErrorHandler = composeException((error, ctx) => { // Log ke external service console.error('[Payment Error]', error);
return ctx.send({ error: 'Payment processing failed', reference: ctx.request.id, }).error();});
export default composeRouter((r) => { r.post('/payment/process', [PaymentController, 'Process']) .exception(PaymentErrorHandler);});Prioritas Exception Handler
Section titled “Prioritas Exception Handler”Error terjadi di handler ↓Ada per-route exception handler? → Ya: Gunakan per-route handler → Tidak: Ada global exception handler? → Ya: Gunakan global handler → Tidak: Return response 500 defaultContoh: Structured Error Handling
Section titled “Contoh: Structured Error Handling”import { composeException } from 'gaman/compose';
class AppError extends Error { constructor( message: string, public statusCode: number = 500, public errors?: Record<string, string[]>, ) { super(message); }}
export default composeException((error, ctx) => { if (error instanceof AppError) { if (error.errors) { return ctx.send({ message: error.message, errors: error.errors }).unprocessable(); } return ctx.send({ message: error.message }).build(error.statusCode); }
// Unknown error console.error('[Unhandled]', error); return ctx.send({ message: 'Internal Server Error' }).error();});Penggunaan di controller:
async Create(ctx) { const body = await ctx.json();
if (!body.email) { throw new AppError('Validation failed', 422, { email: ['Email wajib diisi'], }); }
// ... logic}