How to Add Routes

HTTP routes live in src/routes/<domain>/index.ts. Each file exports a Hono route chain that gets mounted in src/routes/index.ts.

Anatomy of a route file

import { createProjectSchema } from "@backend/features/projects/db/mutations/create-project.mutation";
import { createProject } from "@backend/features/projects/modules/create-project";
import { ApplicationError, ApplicationErrorCode } from "@backend/middleware/error";
import { hasAccess } from "@backend/middleware/permissions/has-access";
import { validate } from "@backend/middleware/validation/validate";
import { getAuthenticatedApp } from "@backend/utils/auth/auth-hono";

type ProjectMutationResponse = { projectId: string };

export const projectRoutes = getAuthenticatedApp()
  .get("/", hasAccess({ action: "read", subject: "project" }), async (ctx) => {
    const { organizationId } = ctx.var;
    const response = await getProjectsList({ organizationId });
    return ctx.json(response);
  })
  .post(
    "/",
    hasAccess({ action: "write", subject: "project" }),
    validate("json", createProjectSchema),
    async (ctx) => {
      const body = ctx.req.valid("json");
      const { projectId } = await createProject({ data: body });
      return ctx.json<ProjectMutationResponse>({ projectId });
    },
  );

Registering routes

Mount routes in src/routes/index.ts:

import { projectRoutes } from "./projects";

export const registerRoutes = (app: Hono) => {
  return app
    .route("/projects", projectRoutes)
    // ... other routes
};

The return type of registerRoutes is what generates the ApiRoutesSdk type for the frontend. Adding a route here automatically exposes it on the frontend SDK.

Validation is mandatory

Every route that accepts input must use the validate() middleware:

// Body validation
validate("json", createProjectSchema)

// Query param validation
validate("query", filtersSchema)

Read validated data with ctx.req.valid("json") or ctx.req.valid("query"). Never use ctx.req.json() directly, since it bypasses validation and breaks the type bridge.

Authentication and permissions

Adding a new route

  1. Create src/routes/<domain>/index.ts
  2. Define routes using getAuthenticatedApp() with validate() middleware
  3. Import and register in src/routes/index.ts with app.route("/prefix", routes)
  4. The frontend SDK picks up the new endpoint automatically