Skip to content

ADR-002: Generate Client from OpenAPI Specification

Status

Accepted

Date: 2024-07-01 (estimated based on initial project setup)

Context

Building an API client for Katana Manufacturing ERP requires:

  • Coverage of 76+ endpoints
  • 150+ data models
  • Full type safety with type hints
  • Both sync and async support
  • Maintenance as API evolves

Options for building the client:

  1. Hand-written client: Write all API methods and models manually
  2. Generated client: Auto-generate from OpenAPI specification
  3. Hybrid approach: Generate base, hand-write wrappers

The Katana API provides an OpenAPI 3.1.0 specification with complete endpoint coverage.

Decision

We will auto-generate the client from the OpenAPI specification using openapi-python-client.

The generation process:

  1. Maintain OpenAPI spec in docs/katana-openapi.yaml
  2. Use openapi-python-client to generate Python client
  3. Automated generation script: scripts/regenerate_client.py
  4. Auto-fix generated code with ruff --unsafe-fixes
  5. Generated code is read-only - never manually edit

Generated code structure:

katana_public_api_client/
├── api/              # 248 endpoint modules (generated)
├── models/           # 337 data models (generated)
├── client.py         # Base client classes (generated)
├── client_types.py   # Type definitions (generated)
├── errors.py         # Error classes (generated)
└── katana_client.py  # Enhanced client (hand-written)

Clear separation:

  • Generated code (api/, models/, client.py, etc.): Never edit manually
  • Custom code (katana_client.py, utils.py): Hand-written enhancements

Consequences

Positive Consequences

  1. Always in Sync: Client stays current with API specification
  2. Type Safety: Full type hints for all models and endpoints
  3. Completeness: 100% endpoint coverage guaranteed
  4. Maintainability: Regenerate on API changes, no manual updates
  5. Reliability: Code generator is well-tested
  6. Both Sync and Async: Generator creates both variants automatically
  7. IDE Support: Full autocomplete and type checking
  8. Documentation: Generated docstrings from OpenAPI descriptions
  9. Zero Manual Boilerplate: 248 endpoint modules + 337 models auto-created

Negative Consequences

  1. Generator Dependency: Dependent on openapi-python-client updates
  2. Generated Code Style: Limited control over generated code style
  3. Breaking Changes: OpenAPI spec changes can break client
  4. Learning Curve: Need to understand generator's patterns
  5. Large Codebase: ~30,000 lines of generated code
  6. Limited Customization: Can't customize generated code directly

Neutral Consequences

  1. OpenAPI Spec Maintenance: Must keep spec updated
  2. Generation Time: ~2 minutes to regenerate client
  3. Build Dependency: Requires npx for generation

Alternatives Considered

Alternative 1: Hand-Written Client

Write all API methods and models manually.

Pros:

  • Full control over implementation
  • Custom patterns and conventions
  • No generator dependency
  • Simpler debugging

Cons:

  • Massive manual effort (248 endpoints × 2 variants = 496 methods)
  • Error-prone (manual typing of 337 models)
  • Hard to keep in sync with API changes
  • No guarantee of completeness
  • Months of initial development

Why Rejected: Too much manual work, prone to errors, hard to maintain.

Alternative 2: Minimal Client + Manual Additions

Generate minimal base client, write wrappers for each endpoint.

Pros:

  • Some automation
  • Can customize wrappers
  • Type safety from generation

Cons:

  • Still requires manual wrappers for 248 endpoints
  • Wrappers break on API changes
  • Duplication between generated and wrapper code
  • Maintenance burden

Why Rejected: Still too much manual work without enough benefit.

Alternative 3: Different Generator

Use alternative OpenAPI generator (e.g., openapi-generator, custom generator).

Pros:

  • Might have different features
  • More customization options

Cons:

  • openapi-python-client is well-maintained and Python-focused
  • Supports OpenAPI 3.1.0
  • Creates clean, idiomatic Python code
  • Active community

Why Rejected: openapi-python-client is the best Python generator available.

Implementation Details

Regeneration Process

uv run poe regenerate-client

The scripts/regenerate_client.py script:

  1. Validates OpenAPI spec with openapi-spec-validator
  2. Validates with Redocly for best practices
  3. Runs openapi-python-client generator
  4. Auto-fixes with ruff check --fix --unsafe-fixes (fixes 6,589+ issues)
  5. Moves generated code to package location
  6. Runs tests to verify

Code Quality Automation

The regeneration automatically fixes:

  • Import sorting and unused imports
  • Code style consistency
  • Unicode character fixes (×→* multiplication signs)
  • Line length and formatting
  • Type hint standardization

No manual patches required - all fixes are automated.

Maintaining Custom Code

Custom enhancements in separate files:

  • katana_client.py: Enhanced client with resilience
  • utils.py: Response unwrapping utilities
  • log_setup.py: Logging configuration

These files are never touched by regeneration.

References