Generated Clients

Responder can generate small API clients from the OpenAPI schema it already builds from your routes, markers, and Pydantic models.

Enable OpenAPI on your app, then write a Python client module:

import responder

api = responder.API(title="Service", version="1", openapi="3.0.2")

@api.get("/users/{user_id}", operation_id="get_user")
def get_user(req, resp, *, user_id: int):
    resp.media = {"id": user_id}

api.generate_client("clients/service.py", class_name="ServiceClient")

Use language= to generate clients for other ecosystems:

api.generate_client(
    "clients/service.ts",
    class_name="ServiceClient",
    language="typescript",
)
api.generate_client("clients/service.js", language="javascript")
api.generate_client("clients/service.rb", language="ruby")
api.generate_client("clients/ServiceClient.php", language="php")

Supported languages are python, javascript, typescript, ruby, and php. The generated modules have no Responder runtime dependency. Python, Ruby, and PHP clients use standard libraries for HTTP calls; JavaScript and TypeScript clients use fetch.

When your OpenAPI schema includes component models, Python and TypeScript clients also generate model types. Request bodies use the request model type, and methods return the documented success response type:

class ItemIn(TypedDict):
    name: str

class ItemOut(TypedDict):
    id: int
    name: str

def create_item(self, body: ItemIn | None = None) -> ItemOut:
    ...
export interface ItemIn {
  name: string;
}

export interface ItemOut {
  id: number;
  name: string;
}

create_item(body: ItemIn | null = null): Promise<ItemOut>
from clients.service import ServiceClient

client = ServiceClient("https://api.example.com", bearer_token="secret")
user = client.get_user(42)

For Python tests, pass Responder’s in-process test client. This lets your generated client exercise the app without a listening socket:

client = ServiceClient(session=api.requests)
assert client.get_user(42) == {"id": 42}

For a fuller example, examples/atelier.py is the canonical contract app: the test suite validates its OpenAPI document, generates a Python client from it, and drives that client against the in-process API.

Python, JavaScript, and TypeScript clients can also validate JSON payloads at runtime. Validation is off by default; pass validate=True in Python or validate: true in JavaScript/TypeScript to check outgoing request bodies and successful responses against the generated OpenAPI schemas:

client = ServiceClient(session=api.requests, validate=True)
client.create_item({"name": "tea"})

If validation fails, the client raises APIValidationError with the schema path that failed, such as response.id expected integer.

When a request fails and the server returns application/problem+json, the generated APIError exposes the parsed payload as problem. Python clients also provide title, detail, and errors convenience attributes:

try:
    client.get_user(404)
except APIError as exc:
    assert exc.problem["status"] == 404
    print(exc.title)

API.generate_client(...) returns source code when no path is supplied:

source = api.generate_client(class_name="ServiceClient")
typescript = api.generate_client(
    class_name="ServiceClient",
    language="typescript",
)

The lower-level helpers are available from responder.ext.clientgen:

from responder.ext.clientgen import generate_client, write_client

source = generate_client(api.openapi, class_name="ServiceClient")
write_client(api.openapi, "clients/service.py", class_name="ServiceClient")
write_client(
    api.openapi,
    "clients/service.ts",
    class_name="ServiceClient",
    language="typescript",
)

The command-line interface can generate clients from an import target too:

responder client app:api > clients/service.py
responder client --lang typescript --class-name ServiceClient \
    --output clients/service.ts app:api

Generated clients include:

  • method signatures generated from path and query parameters,

  • JSON request-body support,

  • bearer, basic, and API-key header helpers,

  • structured APIError exceptions for non-2xx responses,

  • opt-in APIValidationError checks for JSON request/response schemas,

  • real HTTP transport for network calls,

  • Python TypedDict models and TypeScript interfaces for OpenAPI components,

  • typed Python and TypeScript parameters/returns where schemas are available,

  • a Python-only session= hook for Starlette/httpx-style clients in tests.