Skip to main content

A simple OpenAPI client generator using AST transformation

Project description

openapi-to-httpx

CI

An OpenAPI client generator for Python that uses AST transformation to create type-safe HTTP clients.

AST generation of code is a pain, which is why most generation libraries like openapi-generator rely on mustache/jinja code template to populate. But code templates are brittle, rely on manually stringing together whitespace in languages like Python, and have so many edge cases codified in the template they'll make your head spin. Luckily LLMs have very strong performance in writing AST parsers for input code.

Unlike traditional code generators that use templates, this tool:

  1. Defines an ideal, idiomatic Python client structure
  2. Uses AST (Abstract Syntax Tree) manipulation to inject OpenAPI-specific details
  3. Generates clean, type-safe code with full IDE support

This is an experiment in programming 95% of this AST logic via LLMs and agents alone. This trades some code interpretability for speed of development - but we figure that in the AST parsing game, this is best left for machines versus human rules anyway.

Installation

uv sync

Quick Start

# Generate from a URL
uv run openapi-to-httpx https://api.example.com/openapi.json -o ./my_client

# Generate from a local file
uv run openapi-to-httpx ./my-api.yaml -o ./my_client

# Use the built-in Petstore example
uv run openapi-to-httpx --petstore -o ./petstore_client

Generated Client Usage

By default we'll generate an async client so you can use it with non-blocking function calls.

from my_client import APIClient
from my_client.models import Pet

# Initialize the client
client = APIClient(
    base_url="https://api.example.com",
    api_key="your-api-key"  # or bearer_token="..."
)

# No context manager needed!
# All methods return Response[T] with data, status_code, headers, response_time
response = await client.get_pet_by_id(123)
print(f"Pet name: {response.data.name}")
print(f"Response time: {response.response_time}s")

# Create a new pet
new_pet = Pet(name="Fluffy", photoUrls=["https://..."])
response = await client.add_pet(new_pet)

# List pets
response = await client.find_pets_by_status(status="available")
for pet in response.data:
    print(pet.name)

We also support generating a synchronous client by overriding the CLI:

uv run openapi-to-httpx --mode sync {args}

Improving API names

All OpenAPI schemas need to have an operationId. If you're using a framework to auto-generate these OpenAPI schemas (like FastAPI or gin-swagger), these names might be overly verbose like:

stop_execution_api_v1_execute__session_id__stop__execution_id__delete

That's pretty verbose. In every OpenAPI markup library under the sun you can override these names. Do something like this in FastAPI:

@app.delete("/api/v1/execute/{session_id}/stop/{execution_id}", operation_id="stopExecution")
async def stop_execution_api_v1_execute__session_id__stop__execution_id__delete():
    ...

Test Conventions

Testing auto-generated code is not trivial. We take the following general approach to keep our testing relatively straightforward:

  • Specify all desired behavior and edge cases within full OpenAPI files. These files will demonstrate the issue at play.
  • Generate the full client implementations and place these in fixtures/libraries so we can import the real code and benefit from our static typechecking to flag any errors
  • Mock out the expected endpoints with pytest-httpx
  • Add a new unit test that will call the client implementations and assert values. Because we're dealing with the actual client code, this lets us stress test the expected response as real runtime Python objects

Features

  • Type-safe: Full type hints for all parameters and return values
  • Idiomatic Python: Direct method calls, snake_case naming, optional parameters
  • Rich responses: Returns Response[T] with data, status_code, headers, and timing
  • Error handling: Custom exceptions for common HTTP errors
  • Pydantic models: Auto-generated models with validation
  • Clean separation: Models in separate file for better organization
  • Connection pooling: Reuses httpx clients for efficiency
  • CI/CD Ready: GitHub Actions workflow with linting, type checking, and tests

How It Works

  1. Template Definition (ideal_client.py): Defines the perfect Python HTTP client interface
  2. AST Parsing: Parses the template into an Abstract Syntax Tree
  3. Schema Analysis: Reads the OpenAPI specification
  4. AST Transformation: Injects endpoints, models, and parameters into the AST
  5. Code Generation: Outputs clean, formatted Python code

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

openapi_to_httpx-0.1.3.tar.gz (660.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

openapi_to_httpx-0.1.3-py3-none-any.whl (669.1 kB view details)

Uploaded Python 3

File details

Details for the file openapi_to_httpx-0.1.3.tar.gz.

File metadata

  • Download URL: openapi_to_httpx-0.1.3.tar.gz
  • Upload date:
  • Size: 660.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for openapi_to_httpx-0.1.3.tar.gz
Algorithm Hash digest
SHA256 e35bfda23ed463a7956df242afc323e390e2d928fa61e0a1e48c9623674ec5ac
MD5 a97d469a3a1f097866ad7033ecfb6665
BLAKE2b-256 5da43b751cb57839a78c1c421c753d91c6fda9ec77b2db0b22e90749ba63c5df

See more details on using hashes here.

Provenance

The following attestation bundles were made for openapi_to_httpx-0.1.3.tar.gz:

Publisher: ci.yml on piercefreeman/openapi-to-httpx

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file openapi_to_httpx-0.1.3-py3-none-any.whl.

File metadata

File hashes

Hashes for openapi_to_httpx-0.1.3-py3-none-any.whl
Algorithm Hash digest
SHA256 c9c8f6f66ded45e55026277f4389a98e94863c6b3481d39641e54977ad66296d
MD5 f9200b77d466c4afb8fdcb63944148cd
BLAKE2b-256 4fc3b98f7ca6fa3668b007096961c95b6145f7cfc4319fb1174cf20e6525c4c8

See more details on using hashes here.

Provenance

The following attestation bundles were made for openapi_to_httpx-0.1.3-py3-none-any.whl:

Publisher: ci.yml on piercefreeman/openapi-to-httpx

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page