Responses
Declare status-keyed responses and choose the right return shape.
HTTP routes declare responses by status code.
responses: {
200: todoSchema,
404: z.object({
code: z.literal("TODO_NOT_FOUND"),
}),
}
There is no separate errors field. Declared non-2xx responses are part of the
route contract.
Response Schemas
Response body declarations can be Standard Schema-compatible schemas.
responses: {
200: z.object({
id: z.string(),
title: z.string(),
completed: z.boolean(),
}),
}
Use noBody() for statuses without a body.
import { noBody } from "@rest-rpc/core";
responses: {
204: noBody(),
}
Custom and streaming bodies are covered in advanced docs.
Handler Returns
Handlers can always return an explicit response envelope.
return {
status: 404,
body: {
code: "TODO_NOT_FOUND",
},
};
If a route has exactly one successful response, the handler can return the success body directly.
return {
id: "todo_1",
title: "Write docs",
completed: false,
};
That shortcut is only valid because the success status is unambiguous.
Explicit Success
Use an envelope when the status is part of the result.
create({ title }) {
return {
status: 201,
body: createTodo({ title }),
};
}
Declared Error Responses
Declared non-2xx responses need an explicit envelope.
get({ id }) {
const todo = todos.get(id);
if (!todo) {
return {
status: 404,
body: {
code: "TODO_NOT_FOUND",
},
};
}
return todo;
}
You can also use ContractResponseError to throw a declared error response when that’s more convenient.
throw new ContractResponseError(api.todos.get, {
status: 404,
body: {
code: "TODO_NOT_FOUND",
},
});
Client Responses
Every HTTP route exposes fetchResponse().
const response = await api.todos.get.fetchResponse({
id: "todo_1",
});
It returns declared responses as values.
if (response.declared && response.status === 200) {
response.body;
}
if (response.declared && response.status === 404) {
response.body.code;
}
It also exposes undeclared responses.
if (!response.declared) {
throw new Error(`Unexpected response: ${response.status}`);
}
Routes with one successful response also expose fetch().
const todo = await api.todos.get.fetch({ id: "todo_1" });
fetch() returns the successful response body directly. It throws when the
response is undeclared or is not a declared success response. Use it when you don’t care about the status and just want the success body.