Lewati ke konten

Exceptions

GamanJS menyediakan composeException untuk menangani error yang terjadi saat proses request. Exception handler bisa didaftarkan secara global (semua route) atau per-route.

src/modules/app/exceptions/GlobalException.ts
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.

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.

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);
});
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 default
src/modules/app/exceptions/GlobalException.ts
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
}