Skip to content
brix.v2 stable

Search documentation

70 guides

Documentation menu
Docs / APIs and data / API contractsRead Markdown ↗

API server contracts and routes

Define a universal typed API contract, implement its server-only route, and let Brix discover and register the endpoint.

Define a contract

import { createApiContract } from "#brix";
import { z } from "brix/zod";

export const updateProfileApiContract = createApiContract({
  method: "POST",
  path: "/api/profiles/:profileId",
  body: z.object({ displayName: z.string().min(1) }),
  response: z.object({ id: z.string(), displayName: z.string() }),
});

Path parameters are inferred from :profileId. GET contracts cannot have a body. Body and query callers provide schema input; handlers receive parsed output. A response schema describes JSON wire input, while clients receive its parsed output.

API paths follow the same portable route grammar as pages: optional parameters are terminal, and constraints reject anchors, alternation, lookarounds, empty matches, and nonterminal slash-spanning patterns.

Use .returns<Type>() only when compile-time response typing is sufficient. Prefer a Zod response when external data should be checked at runtime.

Conventional routes live at src/features/<feature>/api/<action>/route.ts and export exactly one runtime value named *ApiRoute.

Implement the server route

import { createApiRoute } from "#brix/server";
import { updateProfileApiContract } from "./contract.ts";

export const updateProfileApiRoute = createApiRoute(updateProfileApiContract, {
  auth: true,
  middleware: [rateLimitMiddleware],
  handler: async (_c, { body, params }) => {
    const profile = await saveProfile(params.profileId, body);
    return { id: profile.id, displayName: profile.displayName };
  },
});

Return plain JSON data; Brix normalizes, validates, and responds. undefined produces 204. Invalid successful output and unexpected failures reach the application's error policy. A deliberate Hono HTTPException passes through. auth: true requires the server authentication integration described in server setup.

Routes are discovered automatically. Do not mount them manually or import route.ts into browser code. Server code can call route.execute(c, options) directly without HTTP or middleware; auth context and input/output types remain checked.

Continue with call api contracts.