The handleError function is an error handler for Hono applications that converts EventFabric exceptions to structured HTTP JSON responses.
An in Depth Example
This guide also has an in depth example of a working application built with EventFabric. Combining DDD, CQRS and Event Sourcing.
Check out the In Depth Example page to learn how everything is connected and works out in a real-world application.
import { Hono } from "hono";
import { handleError } from "@nimbus-cqrs/hono";
const app = new Hono();
// Register the error handler
app.onError(handleError);
When a EventFabric exception is thrown, the handler returns a JSON response with the following structure:
{
"error": "EXCEPTION_NAME",
"message": "Human-readable error message",
"details": { ... }
}
| Field | Description |
|---|
error | The exception name (e.g., NOT_FOUND, INVALID_INPUT) |
message | The error message provided when throwing the exception |
details | Optional additional details (only included if provided) |
The HTTP status code is taken directly from the exception’s statusCode property:
| Exception | Status Code | Response error |
|---|
GenericException | 500 | GENERIC_EXCEPTION |
InvalidInputException | 400 | INVALID_INPUT |
NotFoundException | 404 | NOT_FOUND |
UnauthorizedException | 401 | UNAUTHORIZED |
ForbiddenException | 403 | FORBIDDEN |
| Custom exceptions | (custom) | (custom name) |
The handler logs errors differently based on the status code:
| Status Code | Log Level | Description |
|---|
| 5xx | error | Server errors that need investigation |
| 4xx | debug | Client errors, typically expected |
| Unhandled | critical | Non-EventFabric errors, unexpected failures |
import { Hono } from "hono";
import { handleError } from "@nimbus-cqrs/hono";
import { NotFoundException, InvalidInputException } from "@eventfabric-cqrs/core";
const app = new Hono();
app.get("/users/:id", async (c) => {
const user = await findUser(c.req.param("id"));
if (!user) {
throw new NotFoundException("User not found", {
userId: c.req.param("id"),
});
}
return c.json(user);
});
app.post("/users", async (c) => {
const body = await c.req.json();
if (!body.email) {
throw new InvalidInputException("Email is required", {
field: "email",
});
}
const user = await createUser(body);
return c.json(user, 201);
});
app.onError(handleError);
NotFoundException (404):
{
"error": "NOT_FOUND",
"message": "User not found",
"details": {
"userId": "123"
}
}
InvalidInputException (400):
{
"error": "INVALID_INPUT",
"message": "Email is required",
"details": {
"field": "email"
}
}
Unhandled Error (500):
{
"error": "INTERNAL_SERVER_ERROR"
}
import { Hono } from "hono";
import { correlationId, handleError, logger } from "@nimbus-cqrs/hono";
import { setupLogger, parseLogLevel } from "@eventfabric-cqrs/core";
setupLogger({
logLevel: parseLogLevel(process.env.LOG_LEVEL),
});
const app = new Hono();
app.use(correlationId());
app.use(logger({ enableTracing: true }));
// Your routes here
app.get("/health", (c) => c.json({ status: "ok" }));
// Error handler must be registered last
app.onError(handleError);
export default app;