defineHandler
The defineHandler function is the core building block for creating API endpoints in Toapi. It ensures end-to-end type safety by connecting your request schema validation with your implementation logic. A route module typically exports one handler per HTTP method (GET, POST, PUT, PATCH, DELETE).
import { defineHandler, TResponse } from "@toapi/server";import { z } from "zod";
export const GET = defineHandler( { authorize: () => true, query: { limit: z.coerce.number().min(1).default(10), }, }, async (req) => { const { limit } = req.query(); return TResponse.json({ limit }); },);Signature
Section titled “Signature”function defineHandler<Response, AuthData, Params, Query, Body>( schema: Schema<Response, AuthData, Params, Query, Body>, handler: ( req: TRequest<AuthData, Params, Query, Body>, ) => Promise<TResponse<Response>>,): Handler;Parameters
Section titled “Parameters”schema
Section titled “schema”An object defining the input validation, authorization logic, and response shape.
| Property | Type | Description |
|---|---|---|
authorize |
(req: TRequest) => AuthData | Promise<AuthData> |
Required. Determines whether the request is allowed. Return a falsy value (or throw) to deny access — the request is rejected with 401 Unauthorized. The return value is accessible via req.auth(). |
params |
Record<string, ZodType> |
Optional. A map of Zod schemas validating path parameters (e.g. /users/:id). |
query |
Record<string, ZodType> |
Optional. A map of Zod schemas validating query-string parameters. |
body |
ZodType |
Optional. Zod schema validating the JSON request body, parsed and validated lazily by req.data(). |
response |
ZodType |
Optional. Zod schema describing the success response. Validated at runtime after the handler returns, and used to describe the 200 response in the generated OpenAPI document. |
handler
Section titled “handler”The implementation function that receives the validated request and returns a response.
- Argument:
req— aTRequestobject with typed, validated accessors. - Returns: a promise resolving to a
TResponse.
Examples
Section titled “Examples”Basic GET route
Section titled “Basic GET route”export const GET = defineHandler( { authorize: () => true }, async () => { return TResponse.json({ message: "Hello World" }); },);Route with path parameters
Section titled “Route with path parameters”For a route defined as /users/:id:
export const GET = defineHandler( { authorize: () => true, params: { id: z.string().uuid(), }, }, async (req) => { const { id } = req.params(); return TResponse.json({ userId: id }); },);POST route with body validation
Section titled “POST route with body validation”export const POST = defineHandler( { authorize: (req) => { if (!req.headers.get("Authorization")) throw new HttpError(401, "Unauthorized"); return { userId: "current-user" }; }, body: z.object({ title: z.string().min(3), content: z.string(), }), }, async (req) => { const user = req.auth(); const { title, content } = await req.data();
// Perform database operation...
return TResponse.json({ success: true, author: user.userId }); },);POST route with form-data validation
Section titled “POST route with form-data validation”export const POST = defineHandler( { authorize: (req) => { if (!req.headers.get("Authorization")) throw new HttpError(401, "Unauthorized"); return { userId: "current-user" }; }, }, async (req) => { const user = req.auth();
// For multipart/form-data, read the body with `req.formData()` inside the // handler. The `body` schema is for JSON payloads (parsed from `req.json()`). const formData = await req.formData(); const parsed = z .object({ title: z.string().min(3), content: z.string(), }) .parse({ title: formData.get("title"), content: formData.get("content"), });
return TResponse.json({ success: true, title: parsed.title, author: user.userId }); },);