Web
Create HTTP handlers for runtimes that use standard Request and Response.
Use @rest-rpc/web when your server runtime or framework route gives you a
standard Request and expects a standard Response.
@rest-rpc/web creates handlers. It does not register routes with a framework
router, and it only supports HTTP routes.
Install
pnpm add @rest-rpc/core @rest-rpc/web
Catch-all Handler
Use createHandler() when one route or runtime entrypoint should serve a
contract tree.
import { initWeb } from "@rest-rpc/web";
import { api } from "./contract";
type Context = {
env: Env;
ctx: ExecutionContext;
};
const web = initWeb<Context>();
const todoRoutes = web.routes(api.todos, {
list: web.route(api.todos.list, async ({ context }) => {
return listTodos(context.env.DB);
}),
create: web.route(api.todos.create, async ({ title, context }) => {
return createTodo(context.env.DB, title);
}),
});
const apiRoutes = web.routes(api, {
todos: todoRoutes,
});
const handleApiRequest = web.createHandler(apiRoutes);
export default {
fetch(request, env, ctx) {
return handleApiRequest(request, { env, ctx });
},
};
Requests that do not match the contract return 404.
Single Route Handler
Use createHandler() with route() when the surrounding runtime or framework
route already picked the route.
import { initWeb } from "@rest-rpc/web";
import { api } from "./contract";
const web = initWeb<{ request: Request }>();
const handleGetTodo = web.createHandler(
web.route(api.todos.get, ({ id, context }) => {
const authorization = context.request.headers.get("authorization");
void authorization;
return getTodo(id);
}),
);
export const GET = (request: Request) => {
return handleGetTodo(request, { request });
};
Requests that do not match the route return 404.
Custom Body Parsing
By default, JSON request bodies are parsed with request.json(). Custom body
schemas use request.json() for application/json and request.text() for
other content types.
Use parseBody when a route needs a different Web API body reader.
const handleUpload = web.createHandler(
web.route(api.uploads.create, createUpload),
{
parseBody: ({ request }) => request.formData(),
},
);
Error Handling
Use errorHandlers to customize server-generated error responses. Declared
responses returned from handlers, including ContractResponseError, do not run
through these hooks.
const handleApiRequest = web.createHandler(apiRoutes, {
errorHandlers: {
onRequestValidationError: ({ issues }) => ({
status: 422,
body: { code: "VALIDATION_ERROR", issues },
}),
onUnhandledError: () => ({
status: 500,
body: { code: "INTERNAL_SERVER_ERROR" },
}),
},
});