Response Schemas

Response schemas define the allowed outcomes of an operation. They are the contract your generated clients consume and your generated server handlers must return.

Define responses with defineResponse

Here is a simple success response and a reusable error response for the todo example:

import { defineResponse, HttpStatusCode } from "@rexeus/typeweaver-core";
import { z } from "zod";

const todoSchema = z.object({
  id: z.string(),
  title: z.string(),
  completed: z.boolean(),
});

export const GetTodoSuccessDefinition = defineResponse({
  name: "GetTodoSuccess",
  statusCode: HttpStatusCode.OK,
  description: "Todo retrieved successfully",
  body: todoSchema,
});

export const ValidationErrorDefinition = defineResponse({
  name: "ValidationError",
  statusCode: HttpStatusCode.BAD_REQUEST,
  description: "Request validation failed",
  body: z.object({
    message: z.string(),
  }),
});

export const TodoNotFoundErrorDefinition = defineResponse({
  name: "TodoNotFoundError",
  statusCode: HttpStatusCode.NOT_FOUND,
  description: "Todo was not found",
  body: z.object({
    message: z.string(),
    todoId: z.string(),
  }),
});

Then attach them to the operation:

responses: [
  GetTodoSuccessDefinition,
  TodoNotFoundErrorDefinition,
  ValidationErrorDefinition,
],

Rules worth remembering

Response names must be globally unique

Response names are not scoped to one operation. GetTodoSuccess and TodoNotFoundError must be unique across the whole spec.

That uniqueness is what lets Typeweaver generate stable types and validators without collisions.

Put the success response first

The first item in responses is the success case. Keep that ordering intentional.

Reuse shared responses

Common errors such as ValidationError can be defined once and reused across many operations. This keeps contracts consistent and reduces copy-paste drift.

Why response design matters

Clear response schemas help both sides of the contract:

  • generated clients can safely discriminate on response.type
  • generated server integrations know which response shapes are valid
  • handlers stay honest about success and error outcomes

If your responses are vague, the generated code becomes less helpful. If your responses are explicit, the generated code does more work for you.

A note on derived responses

If you want to start from a shared base response and specialize it, Typeweaver also supports defineDerivedResponse. For a first project, plain defineResponse plus shared reusable responses is usually enough.

Was this page helpful?