Your route table is a plain object. Keys are path patterns, values are handler functions. See Request for what a handler receives.
const routes = {
"/hello": () => res("Hello World!"),
"/users/:id": ({ matches }) => res({ id: matches.params.id }),
"/posts/:id/comments/:commentId": getPostComment
};Path parameters
Patterns use path-to-regexp syntax. Named parameters arrive on matches.params, already decoded.
"/users/:id" -> /users/42 matches.params.id === "42"
"/posts/:id/comments/:commentId" -> /posts/5/comments/10
"/files/:path*" -> /files/a/b/c matches.params.path === "a/b/c"HTTP methods
A route matches every method. Branch inside the handler on request.method, and answer anything you do not support with res_405.
1const routes = {2 "/users/:id": async ({ request, matches, body, state }) => {3 const id = matches.params.id;4 5 if (request.method === "GET") return res(await state("Users", id).get("profile"));6 if (request.method === "POST") {7 await state("Users", id).put({ profile: body });8 return res_201();9 }10 11 return res_405();12 }13};For larger APIs, define handlers as named functions in their own modules and reference them directly by name — there is no separate registration step.
Matching order
The first pattern that matches wins, so declare specific paths before catch-alls. If nothing matches, Apiker answers 404. If a handler returns nothing, the response is 204.
Enabling authRoutes or adminPanel prepends those routes to your table, so they are matched before your own.


