Skip to main content

Pagination Example

Paginate a list using a validated query and advertise totals via ctx.set.

src/api/posts/schema.ts
import { z } from "zod";

export const GET = {
query: z.object({
page: z.coerce.number().int().min(1).default(1),
limit: z.coerce.number().int().min(1).max(50).default(20),
}),
};
src/api/posts/route.ts
import { defineRoute } from "burger-api";
import { GET as GETSchema } from "./schema";
import { posts } from "./store";

export const GET = defineRoute(GETSchema, (ctx) => {
const { page, limit } = ctx.validated.query;
const start = (page - 1) * limit;
const items = posts.slice(start, start + limit);

ctx.set = {
headers: {
"x-total": String(posts.length),
"x-page": String(page),
"x-limit": String(limit),
},
};
return Response.json({ items });
});

The query is validated against schema.ts, so page and limit are numbers, and ctx.set applies the pagination headers once at the end of the request lifecycle. See also the CRUD API.