Skip to main content

Hono example

The apps/example-hono directory contains a working Hono API that wires every @rtorcato/api-* package together. The API contract is identical to the Express example — same routes, same response shapes — so you can compare the two implementations side by side.

What it demonstrates

PackageUsage in the example
api-configloadEnv() validates PORT + LOG_LEVEL from .env at startup
api-loggercreateLogger() gives a pino logger, pretty-printed in dev
api-errorsNotFoundError is thrown when an item ID doesn't exist
api-errors-honoerrorHandler() + notFoundHandler via app.onError / app.notFound
api-rate-limitcreateRateLimiter() — 100 req/min sliding window keyed on forwarded IP
api-responseok() wraps every success payload in { success: true, data }
api-validationvalidate() parses POST bodies and throws BadRequestError on failure
@hono/swagger-uiSwagger UI at /api-docs; raw spec served at /api-docs/json

Routes

GET /items
POST /items { "name": string }
GET /items/:id
DELETE /items/:id
GET /api-docs Swagger UI
GET /api-docs/json raw OpenAPI spec

Items are stored in-memory — no database required.

Run locally

cd apps/example-hono
cp .env.example .env
pnpm dev

The server starts on http://localhost:3002 with pretty-printed logs.

  • Swagger UI → http://localhost:3002/api-docs
  • Raw spec → http://localhost:3002/api-docs/json

Run with Docker

cd apps/example-hono
docker compose up

The image builds from the monorepo root, installs workspace packages, and starts the server on port 3002.

Quick smoke test

# List items (empty)
curl http://localhost:3002/items

# Create
curl -X POST http://localhost:3002/items \
-H 'Content-Type: application/json' \
-d '{"name":"world"}'

# 404 for a bad ID
curl http://localhost:3002/items/bad-id

# 400 validation error — missing name
curl -X POST http://localhost:3002/items \
-H 'Content-Type: application/json' \
-d '{}'

Source

apps/example-hono/src/index.ts