Skip to content

Repository files navigation

openapi-python

QAReleasePyPI

openapi-python generates typed Python API clients from OpenAPI specs, with a developer-friendly and ergonomic string-literal-based interface strongly inspired by openapi-typescript.

openapi-python demo

Installation

uv add openapi-python[httpx] # Ships with an `httpx` transport
uv add openapi-python # Bring your own transport (requests, asyncio, ...)

Client generation

Generate a client from an OpenAPI spec in openapi.json:

# Types + Protocol + HTTP transport
uv run openapi-python generate --spec ./openapi.json --out ./generated
# Types + Protocol
uv run openapi-python generate --spec ./openapi.json --out ./generated --protocol-only

Using generated clients

Generated clients expose route-specific callables with typed params, query, headers, body, and return values.

When using openapi-python[httpx]:

importhttpxfromgenerated.my_clientimportAsyncClient, Client, DefaultAsyncTransport, DefaultTransportsync_http=httpx.Client(
base_url="https://api.example.com",
headers={"authorization": "Bearer token"},
)
async_http=httpx.AsyncClient(
base_url="https://api.example.com",
headers={"authorization": "Bearer token"},
)
client=Client(
transport=DefaultTransport(client=sync_http),
)
async_client=AsyncClient(
transport=DefaultAsyncTransport(client=async_http),
)
book=client.get("/books/{book_id}")(params={"book_id": 1})
async_book=awaitasync_client.get("/books/{book_id}")(params={"book_id": 1})

When using openapi-python, or for --protocol-only clients, provide your own transport:

fromgenerated.my_clientimportClientclient=Client(transport=my_transport)
book=client.get("/books/{book_id}")(params={"book_id": 1})

See Custom transport on how to build a custom transport.

Protocols

Generated clients expose a transport protocol. You can plug in your own transport while keeping route-level typing guarantees.

Use --protocol-only to generate clients that don't ship with a built-in transport.

Protocol typing can be relaxed independently with --no-routes, --no-requests, and --no-responses.

Custom transport

Install openapi-python without extras and generate protocol-only code:

uv add openapi-python requests
uv run openapi-python generate \
--spec ./openapi.json \
--out ./generated \
--package my_client \
--protocol-only

Then provide an object that satisfies the generated Transport protocol:

fromcollections.abcimportMappingimportrequestsfromgenerated.my_clientimportClientclassRequestsTransport:
defrequest(
self,
*,
method: str,
route: str,
base_url: str,
params: Mapping[str, object] |None,
query: Mapping[str, object] |None,
headers: Mapping[str, object] |None,
request_media_type: str|None,
body: object|None,
response_media_type: str|None,
) ->object:
request_kwargs= {"json": body}
ifrequest_media_typeandrequest_media_type!="application/json":
request_kwargs= {"data": body}
response=requests.request(
method=method.upper(),
url=f"{base_url.rstrip('/')}{route.format(**(paramsor {}))}",
params={key: str(value) forkey, valuein (queryor {}).items()} orNone,
headers={key: str(value) forkey, valuein (headersor {}).items()} orNone,
**request_kwargs,
)
response.raise_for_status()
ifresponse.content:
returnresponse.json()
returnNoneclient=Client(
transport=RequestsTransport(),
)
book=client.get("/books/{book_id}")(params={"book_id": 1})

About

The Python-version of openapi-typescript. Generates typed Python API clients from OpenAPI specs with a developer-friendly and ergonomic string-literal-based interface.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages