Skip to main content

Express example

The apps/example-express directory contains a working Express 5 API that wires every @rtorcato/api-* package together so you can see how they interact in a real server.

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-authsignToken() issues a JWT on POST /login
api-auth-expressauthMiddleware() guards GET /me
api-errorsNotFoundError is thrown when an item ID doesn't exist
api-errors-expresserrorHandler() + notFoundHandler convert those errors to JSON; asyncHandler() wraps async routes
api-express-utilsgetIP() keys the rate limiter; logRoutes() prints routes on start
api-security-expresssecurityMiddleware() sets helmet security headers on every response
api-cors-expresscorsMiddleware() applies the CORS policy
api-timeout-expresstimeoutMiddleware({ ms }) — a slow request is failed with a 503 instead of hanging
api-rate-limit-expressrateLimitMiddleware() — 100 req/min sliding window, in-memory
api-webhooks-expresswebhookMiddleware() verifies an HMAC signature on POST /webhooks (opt-in via webhookSecret)
api-healthcreateHealthRegistry() tracks the readiness checks
api-health-expresslivenessHandler() / readinessHandler() back /healthz + /readyz
api-uploaduploadFile() streams POST /upload to S3 (wired when an S3 client is provided)
api-validationvalidate() parses POST bodies and throws BadRequestError on failure
api-responseok() wraps every success payload in { success: true, data }
api-openapiOpenAPI spec defined in src/spec.ts; generateScalarHtml / generateSwaggerHtml render the UI pages
api-openapi-expressserveApiDocs() mounts Scalar UI at /api-docs; serveSwaggerDocs() mounts Swagger UI at /swagger
api-graceful-shutdowncreateShutdownController() drains the server on SIGTERM/SIGINT (in index.ts)

Routes

GET /items
POST /items { "name": string }
GET /items/:id
DELETE /items/:id
POST /login { "username": string } → { token }
GET /me Bearer token required
POST /upload multipart file → S3 (when an S3 client is configured)
POST /webhooks HMAC-verified receiver (when webhookSecret is set)
GET /healthz liveness probe
GET /readyz readiness probe
GET /api-docs Scalar API reference
GET /api-docs/openapi.json
GET /swagger Swagger UI
GET /swagger/openapi.json

Items are stored in-memory — no database required.

Run locally

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

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

  • Scalar API reference → http://localhost:3001/api-docs
  • Swagger UI → http://localhost:3001/swagger

Run with Docker

cd apps/example-express
docker compose up

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

Quick smoke test

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

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

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

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

Source

apps/example-express/src/index.ts