onError Handler
The handleError function is an error handler for Hono applications that converts Nimbus exceptions to structured HTTP JSON responses.
An in Depth Example
This guide also has an in depth example of a working application built with Nimbus. 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.
Basic Usage
typescript
import { Hono } from "hono";
import { handleError } from "@nimbus-cqrs/hono";
const app = new Hono();
// Register the error handler
app.onError(handleError);Response Format
When a Nimbus exception is thrown, the handler returns a JSON response with the following structure:
json
{
"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) |
Status Code Mapping
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) |
Logging Behavior
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-Nimbus errors, unexpected failures |
Example: Exception Handling
typescript
import { Hono } from "hono";
import { handleError } from "@nimbus-cqrs/hono";
import { NotFoundException, InvalidInputException } from "@nimbus-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);Response Examples
NotFoundException (404):
json
{
"error": "NOT_FOUND",
"message": "User not found",
"details": {
"userId": "123"
}
}InvalidInputException (400):
json
{
"error": "INVALID_INPUT",
"message": "Email is required",
"details": {
"field": "email"
}
}Unhandled Error (500):
json
{
"error": "INTERNAL_SERVER_ERROR"
}Complete Application Setup
typescript
import { Hono } from "hono";
import { correlationId, handleError, logger } from "@nimbus-cqrs/hono";
import { setupLogger, parseLogLevel } from "@nimbus-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;