How to Add a New Route
This guide documents the complete workflow for adding a new HTTP endpoint to the Workers backend, ensuring the OpenAPI spec is generated automatically and the route is validated.
Flow (4 steps)
┌──────────┐ ┌──────────┐ ┌──────────────┐ ┌──────────┐
│ 1. Handler │ → │ 2. Router │ → │ 3. Registry │ → │ 4. Build │
└──────────┘ └──────────┘ └──────────────┘ └──────────┘Step 1 — Create the handler
In workers/src/routes/, create or edit the file for your entity.
Rules:
- Use
createHandler(fn)frommiddleware/handler.ts - Receive the body via
parseBody(request, schema)with Zod schema - Respond with
json({...}) - Use
requireAuthandrequireRolefor access control - Use
idempotentMutationfor mutating endpoints
// workers/src/routes/customers.ts
import { createHandler, parseBody, json } from "../middleware/handler";
import { requireAuth, requireRole } from "../middleware/auth";
import { z } from "zod";
export const customerSchema = z.object({
name: z.string().min(1).max(100),
email: z.string().email(),
});
export const handleCreateCustomer = createHandler(async (request, env, _ctx, corrId) => {
const principal = await requireAuth(request, env);
requireRole(["ADMIN"])(principal);
const payload = await parseBody(request, customerSchema);
// ... business logic ...
return json({ id: "uuid", serverTime: new Date().toISOString() }, 201);
});Step 2 — Register in the router
In workers/src/router.ts, import the handler and add the route:
// 1. Import (at the top)
import { handleCreateCustomer } from "./routes/customers";
// 2. Register (in the createRouter function)
routes["POST /api/v1/customers"] = { handler: handleCreateCustomer };Step 3 — Register in the OpenAPI registry
In scripts/openapi-registry.ts, add an entry in the routeRegistry array (routes are declared with route() helper and declarative middlewares in router.ts):
{
method: "POST",
path: "/api/v1/customers",
summary: "Create customer",
description: "Creates a new customer record.",
tags: ["Customers"],
auth: "admin",
requestSchema: customerSchema, // ← from your schemas file
requestExample: {
name: "João Exemplo",
email: "joao@exemplo.com",
},
responseSchema: createResponseSchema, // ← reuse or create a new one
responseDescription: "Customer created",
statusCodes: [201, 400, 401, 403],
},Required fields: method, path, summary, tags, auth, statusCodes.
Optional fields: description, requestSchema, requestExample, responseSchema, responseDescription.
Step 4 — Validate and generate
pnpm docs:openapi # Validates coverage + generates openapi.json
pnpm docs:build # Runs everything above + builds the portalIf step 2 or 3 is missing, the build fails with a clear error.
auth Values
| Value | Meaning |
|---|---|
"none" | Public endpoint (health, login) |
"bearer" | Any authenticated user |
"admin" | Requires ADMIN role |
"cadastro" | Requires ADMIN or CADASTRO |
"chamador" | Requires ADMIN or CHAMADOR |
"relatorios" | Requires ADMIN or RELATORIOS |
Automatic Validation
The scripts/generate-openapi.ts script performs two checks:
- Every route in
router.tshas a registry entry — if missing, error and build breaks - No orphan registry entries — warning if there's an entry without a matching route
⚠️ If you add a new route and forget to register it in OpenAPI,
pnpm docs:buildfails withRoute GET /api/v1/customers is NOT documented.