๐ŸŒ AIๆœ็ดข & ไปฃ็† ไธป้กต
Skip to content

hardbyte/rust-python-codegen-comparison

Repository files navigation

Rust โ†” Python Codegen Demo

This repository compares two approaches for delivering the same API surface from Rust to Python:

  • shared_models/ โ€“ a lightweight crate that defines all DTOs/enums once and conditionally derives utoipa and reflectapi traits so each server emits the same schema.
  • axum_server/ โ€“ an Axum application annotated with utoipa that exposes REST endpoints and an OpenAPI document at runtime.
  • reflect_server/ โ€“ a code-first reflectapi service that builds an identical schema and streams the specification as both Reflect JSON and OpenAPI.
  • Generated clients โ€“ axum-server-client/ and reflect-api-demo-client/ are regenerated automatically by ./test-ci.sh so that the Python examples always match the latest schema.

By sharing the types the two servers emit byte-identical payloads while covering richer features: timestamps (chrono::DateTime<Utc>), enums, optional fields, and structured error payloads.

API Surface

REST API (Axum + utoipa)

Method Path Description
GET /health Health check with timestamp
GET /users List all users
GET /users/{id} Fetch a single user by id
POST /users Create a user with validation

All error responses use { "code": string, "message": string, "detail"?: string } and appropriate HTTP status codes.

RPC API (ReflectAPI)

Operation Route HTTP Methods Notes
health.get /health.get GET, POST Same payload as the REST /health route
users.list /users.list GET, POST Enumerates users
user.get /user.get POST Accepts { "id": number }
user.create /user.create POST Validates username/email/roles

HTTP Method Support:

  • Operations without parameters (health.get, users.list): Support both GET and POST
  • Operations with parameters (user.get, user.create): POST only with JSON request body

The generated OpenAPI document is normalized so that enums appear as standard enum values, keeping the Python generator happy.

Shared data types

  • User
    • id: u64
    • username, email
    • created_at: DateTime<Utc>
    • roles: [admin|editor|viewer]
    • status: [active|invited|suspended]
    • preferences?: { theme, timezone?, last_login_at? }
  • HealthStatus
    • status
    • checked_at: DateTime<Utc>
    • region?
  • ApiError
    • code, message, detail?
  • CreateUserRequest
    • username, email
    • roles?, timezone?

These types are reused verbatim in both the utoipa and reflectapi servers.

End-to-End Workflow

  1. Install prerequisites

    • Rust (stable channel)
    • Python 3.12+
    • uv
  2. Run the local CI harness

    ./test-ci.sh

    The script:

    • Runs cargo fmt + cargo clippy
    • Builds both servers in release mode
    • Boots the binaries and waits for readiness
    • Downloads and normalizes the OpenAPI specs
    • Regenerates the Python clients with openapi-python-client
    • Runs the Python examples and test suite to verify functionality
  3. Start servers manually

    # Start Axum/utoipa server (port 8000)
    cargo run --release --bin axum_server
    
    # Start ReflectAPI server (port 9000)
    cargo run --release --bin reflect_server
  4. Generate Python clients manually

    # Generate client for Axum REST API
    uv run openapi-python-client generate --url http://127.0.0.1:8000/api-docs/openapi.json --meta uv --overwrite
    
    # Generate client for ReflectAPI Server (using git version with Python support)
    cargo install --git https://github.com/thepartly/reflectapi reflectapi-cli
    reflectapi codegen --language python --schema reflect_server/reflectapi.json \
      --output reflect-api-demo-client/reflect_api_demo_client \
      --python-package-name "reflect_api_demo_client" --python-async
  5. Initialize the uv workspace and run Python demos

    # Sync workspace dependencies (creates proper local package links)
    uv sync
    
    # Run simple examples
    uv run python axum_example.py      # REST API simple example
    uv run python reflect_example.py   # RPC API simple example
    
    # Run interactive TUI demo for presentations
    uv run python demo_tui.py          # Manual control (default)
    uv run python demo_tui.py --auto   # Auto-advance mode
    
    # Run test suite
    uv run pytest test_apis.py -v

The test-ci.sh pipeline mirrors the .github/workflows/ci.yml job so GitHub Actions and local development stay in sync.

Repository Layout

โ”œโ”€โ”€ shared_models/               # Reusable Rust crate with DTOs/enums
โ”œโ”€โ”€ axum_server/                 # Axum + utoipa server (REST API)
โ”‚   โ””โ”€โ”€ src/
โ”‚       โ””โ”€โ”€ main.rs              # Routes, handlers, OpenAPI doc
โ”œโ”€โ”€ reflect_server/              # reflectapi builder + Axum host (RPC API)
โ”‚   โ””โ”€โ”€ src/
โ”‚       โ”œโ”€โ”€ lib.rs               # Builder using shared models with tags
โ”‚       โ””โ”€โ”€ main.rs              # Spec export + Axum bridge
โ”œโ”€โ”€ axum-server-client/          # Generated OpenAPI client for REST server (workspace member)
โ”‚   โ””โ”€โ”€ pyproject.toml           # Modern pyproject.toml for uv
โ”œโ”€โ”€ reflect-api-demo-client/     # Generated OpenAPI client for RPC server (workspace member)
โ”‚   โ””โ”€โ”€ pyproject.toml           # Modern pyproject.toml for uv
โ”œโ”€โ”€ axum_example.py              # Simple example client for REST API
โ”œโ”€โ”€ reflect_example.py           # Simple example client for RPC API
โ”œโ”€โ”€ demo_tui.py                  # Interactive TUI demo for presentations
โ”œโ”€โ”€ test_apis.py                 # Pytest test suite for both APIs
โ”œโ”€โ”€ pyproject.toml               # uv workspace root with local dependencies
โ”œโ”€โ”€ test-ci.sh                   # Local CI + codegen harness
โ””โ”€โ”€ .github/workflows/ci.yml     # GitHub Actions workflow that runs the same script

Notes

  • Both servers emit Swagger/Redoc UIs (http://127.0.0.1:8000/swagger-ui, http://127.0.0.1:9000/doc).
  • The reflectapi server writes reflect_server/reflectapi.json on startup; test-ci.sh waits for the file before generating clients.
  • Enums, timestamps, optional fields, and structured errors are now first-class in both ecosystems, so the generated Python clients expose type-safe enums and datetime values.
  • If you tweak the schema, rerun ./test-ci.sh to refresh the Python clients and validate the system end-to-end.

About

Example repo showing options to create python clients for rust servers

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published