Skip to main content

OASist Client Generator: generate Python clients from OpenAPI schemas with auto-formatting, custom headers and environment variables

Project description

OASist Client Generator

Generate type-safe Python clients from OpenAPI schemas with a beautiful CLI interface. Supports both JSON and YAML schemas with Orval-inspired configuration.

Built on top of openapi-python-client with enhanced features and developer experience.

Features

  • ๐Ÿš€ Clean, modular Python package with rich CLI interface
  • ๐Ÿ“ฆ Generate type-safe Python clients from OpenAPI specs (JSON/YAML)
  • โœจ Automatic code formatting with Black (optional, enabled by default)
  • ๐Ÿ”„ Schema sanitization and validation with security fixes
  • ๐ŸŽฏ Orval-inspired configuration format with environment variable support
  • ๐Ÿ—๏ธ Built with design patterns (Strategy, Command, Dataclass)
  • โšก Automatic base URL detection and post-hook management
  • ๐ŸŽจ Beautiful terminal UI with progress indicators
  • ๐Ÿ”’ Path traversal protection and input validation
  • ๐Ÿ” Automatic retry logic for common failures

Installation

# Install from PyPI
pip install oasist

# Install with Black formatting support (recommended)
pip install oasist[formatting]

# Or install Black separately
pip install black

Quick Start

# List all configured services
oasist list

# Generate a specific client
oasist generate user

# Generate all clients
oasist generate-all

# Show service details
oasist info user

# Force regenerate existing client
oasist generate user --force

# Use custom config file
oasist -c production.json generate user

# Enable verbose/debug logging
oasist -v generate user

Configuration

The generator supports both JSON and YAML OpenAPI documents. It pre-fetches the schema with optional headers/params, then generates via a local temp file to ensure consistent handling of JSON and YAML. Configuration is provided via a single JSON file using an Orval-inspired "projects" structure.

Environment Variable Substitution

OASist supports environment variable substitution in configuration files using the ${VAR} or ${VAR:default} syntax:

  • ${VAR} - Replace with environment variable value (warns if not found)
  • ${VAR:default} - Replace with environment variable value or use default if not found

Example:

{
  "projects": {
    "api": {
      "input": {
        "target": "${API_SCHEMA_URL:http://localhost:8000/openapi.json}"
      },
      "output": {
        "base_url": "${API_BASE_URL}",
        "dir": "api_client"
      }
    }
  }
}

Create a .env file in your project root:

API_SCHEMA_URL=https://api.production.com/openapi.json
API_BASE_URL=https://api.production.com
API_TOKEN=your_secret_token_here

Custom Headers

You can specify custom headers for schema fetch requests, which is useful for authenticated endpoints:

{
  "projects": {
    "protected_api": {
      "input": {
        "target": "https://api.example.com/openapi.json",
        "headers": {
          "Authorization": "Bearer ${API_TOKEN}",
          "X-Custom-Header": "custom-value"
        }
      },
      "output": {
        "dir": "protected_api_client"
      }
    }
  }
}

Automatic Code Formatting with Black

OASist automatically formats generated Python code using Black (if installed). This ensures clean, consistent code style across all generated clients.

Features:

  • โœ… Enabled by default for all projects
  • โœ… Gracefully skips if Black is not installed (with helpful message)
  • โœ… Can be disabled per-project via configuration
  • โœ… Runs after successful client generation
  • โœ… Uses Black's default configuration (88-character line length)

Configuration:

{
  "projects": {
    "formatted_api": {
      "input": {
        "target": "https://api.example.com/openapi.json"
      },
      "output": {
        "dir": "formatted_client",
        "format_with_black": true  // Default: true
      }
    },
    "unformatted_api": {
      "input": {
        "target": "https://api.example.com/openapi.json"
      },
      "output": {
        "dir": "unformatted_client",
        "format_with_black": false  // Disable formatting
      }
    }
  }
}

Installing Black:

# Install OASist with formatting support
pip install oasist[formatting]

# Or install Black separately
pip install black

What happens if Black is not installed?

  • OASist will log a warning message
  • Generation will continue successfully
  • Code will be generated but not formatted
  • You'll see: "Black is not installed. Skipping code formatting."

Basic Configuration

Create oasist_config.json in your project root:

{
  "output_dir": "./test",
  "projects": {
    "user_service": {
      "input": {
        "target": "http://localhost:8001/openapi.json",
        "prefer_json": true
      },
      "output": {
        "dir": "user_service",
        "name": "User Service",
        "base_url": "http://localhost:8001",
        "package_name": "user_service",
        "format_with_black": true
      }
    },
    "test": {
      "input": {
        "target": "${TEST_SCHEMA_URL}",
        "prefer_json": true,
        "_comment": "Optional headers for the schema fetch request",
        "headers": {
          "Authorization": "Bearer ${API_TOKEN}",
          "X-API-Key": "${API_KEY:default_key}"
        }
      },
      "output": {
        "dir": "test",
        "name": "Test",
        "base_url": "${TEST_BASE_URL}",
        "package_name": "test",
        "format_with_black": true,
        "_comment": "Set format_with_black to false to disable automatic code formatting"
      }
    },
    "local_yaml": {
      "input": {
        "target": "http://localhost:8004/api/schema/"
      },
      "output": {
        "dir": "local_yaml_client",
        "name": "Local YAML API",
        "base_url": "http://localhost:8004",
        "package_name": "local_yaml_client",
        "format_with_black": false
      }
    }
  }
}

Configuration Parameters

Global Parameters

Parameter Required Description
output_dir No Base directory for all generated clients (default: "./clients")
projects Yes Object containing project configurations keyed by project name

Project Input Parameters

Parameter Required Description
target Yes URL to OpenAPI schema endpoint
prefer_json No If true, prefers JSON format over YAML
params No Query parameters for schema fetch requests
headers No Custom HTTP headers for schema fetch requests

Project Output Parameters

Parameter Required Description
dir Yes Directory name for generated client
name Yes Human-readable service name
base_url No Service base URL (auto-detected if not provided)
package_name No Python package name (auto-generated if not provided)
format_with_black No Enable Black code formatting (default: true)

Usage in Code

# Import the generated client
from clients.user_service.user_service_client import Client

# Initialize client
client = Client(base_url="http://192.168.100.11:8011")

# Use the client
response = client.users.list_users()
user = client.users.get_user(user_id=123)

All Commands

Global Options

# Use custom configuration file
oasist -c custom_config.json <command>
oasist --config custom_config.json <command>

# Enable verbose/debug logging
oasist -v <command>
oasist --verbose <command>

# Combine options
oasist -v -c prod.json generate-all

Basic Commands

# Show general help
oasist --help
oasist help

# Show command-specific help
oasist help generate
oasist generate --help

# Show version information
oasist --version

# List all services and their generation status
oasist list

# Show detailed information about a service
oasist info <service_name>

Generation Commands

# Generate client for a specific service
oasist generate <service_name>

# Force regenerate (overwrite existing)
oasist generate <service_name> --force

# Generate clients for all configured services
oasist generate-all

# Generate all with force overwrite
oasist generate-all --force

Project Structure

OASist/
โ”œโ”€โ”€ oasist/                 # Main package
โ”‚   โ”œโ”€โ”€ __init__.py         # Package exports and version
โ”‚   โ”œโ”€โ”€ oasist.py          # Single-file generator implementation
โ”‚   โ””โ”€โ”€ __pycache__/       # Python cache files
โ”œโ”€โ”€ dist/                   # Distribution files (wheels, tarballs)
โ”œโ”€โ”€ venv/                   # Virtual environment
โ”œโ”€โ”€ oasist_config.json      # Configuration file
โ”œโ”€โ”€ example.oasist_config.json  # Example configuration
โ”œโ”€โ”€ pyproject.toml          # Project configuration
โ”œโ”€โ”€ requirements.txt        # Dependencies
โ”œโ”€โ”€ README.md              # This file
โ””โ”€โ”€ test/                  # Generated clients directory (configurable)
    โ”œโ”€โ”€ user_service/      # Generated client example
    โ”‚   โ”œโ”€โ”€ pyproject.toml
    โ”‚   โ””โ”€โ”€ user_service_client/
    โ”‚       โ”œโ”€โ”€ __init__.py
    โ”‚       โ”œโ”€โ”€ client.py
    โ”‚       โ”œโ”€โ”€ api/
    โ”‚       โ”œโ”€โ”€ models/
    โ”‚       โ””โ”€โ”€ types.py
    โ””โ”€โ”€ [other_services]/  # Additional generated clients

Requirements

Core Dependencies

  • Python 3.8+
  • openapi-python-client >= 0.26.1
  • requests >= 2.31.0
  • pyyaml >= 6.0.1
  • rich >= 13.7.0
  • python-dotenv >= 1.0.1

Optional Dependencies

  • black >= 23.0.0 (for automatic code formatting)

Install with formatting support:

pip install oasist[formatting]

Troubleshooting

Schema URL not accessible

Ensure the service is running and the schema endpoint is correct:

curl http://192.168.100.11:8011/api/schema/

Permission errors

Ensure write permissions for the clients directory:

chmod -R u+w clients/

Client generation fails

Check if openapi-python-client is installed:

pip install --upgrade openapi-python-client

Enable debug logging in code:

logging.basicConfig(level=logging.DEBUG)

Black formatting not working

Check if Black is installed:

black --version

Install Black if needed:

pip install black
# Or
pip install oasist[formatting]

Disable formatting if not needed:

{
  "output": {
    "format_with_black": false
  }
}

Design Patterns Used

OASist uses several design patterns to ensure maintainability and extensibility:

  • Strategy Pattern: SchemaParser protocol for pluggable JSON/YAML parsing
  • Command Pattern: CLI commands encapsulate different operations (list, generate, info)
  • Dataclass Pattern: Type-safe ServiceConfig with validation
  • Context Manager: Temporary file management with automatic cleanup
  • Template Method: Generator execution with customizable hooks

Why the Patterns?

While this adds some code complexity, the benefits are:

โœ… Easy to extend - Add new parsers, commands, or validators without touching existing code
โœ… Type-safe - Dataclasses provide validation and IDE autocomplete
โœ… Testable - Each component can be tested independently
โœ… Maintainable - Clear separation of concerns makes debugging easier

For simple use cases, you only interact with the CLI - the patterns are invisible. For advanced use cases, the modular design allows programmatic usage and customization.

Django Integration (Optional)

To use with Django management commands:

# In your Django management command
from oasist import ClientGenerator, ServiceConfig

generator = ClientGenerator(output_base=Path("./clients"))
generator.add_service("user", ServiceConfig(...))
generator.generate("user")

Advanced Usage

Programmatic Usage

from oasist import ClientGenerator, ServiceConfig
from pathlib import Path

# Create generator with custom output directory
generator = ClientGenerator(output_base=Path("./my_clients"))

# Add services
generator.add_service("api", ServiceConfig(
    name="API Service",
    schema_url="https://api.example.com/openapi.json",
    output_dir="api_client",
    format_with_black=True  # Enable Black formatting
))

# Generate
generator.generate("api", force=True)

# Or generate all
generator.generate_all(force=True)

# Note: You can also modify the OUTPUT_DIR constant at the top of the file
# for persistent changes instead of passing output_base parameter

Custom Base URL and Formatting Options

generator.add_service("prod", ServiceConfig(
    name="Production API",
    schema_url="https://api.example.com/openapi.json",
    output_dir="prod_client",
    base_url="https://api.example.com",  # Custom base URL
    format_with_black=True  # Enable automatic Black formatting
))

# Disable formatting for specific service
generator.add_service("legacy", ServiceConfig(
    name="Legacy API",
    schema_url="https://legacy.example.com/openapi.json",
    output_dir="legacy_client",
    format_with_black=False  # Disable formatting for this service
))

Examples

Example 1: Generate User Service Client

$ oasist generate user_service
INFO: โœ“ Generated client: user_service โ†’ test/user_service

Example 2: List All Services

$ oasist list

๐Ÿ“‹ Configured Services:
  โ—‹ user_service        User Service                  http://localhost:8001/openapi.json
  โ—‹ communication_service Communication Service       http://localhost:8002/openapi.json
  โ—‹ local_yaml          Local YAML API                http://localhost:8004/api/schema/

Example 3: Service Information

$ oasist info user_service

๐Ÿ“ฆ Service: user_service
   Name:        User Service
   Schema URL:  http://localhost:8001/openapi.json
   Output:      test/user_service
   Status:      Not generated

Contributing

Contributions are welcome! To extend or modify:

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes with appropriate tests
  4. Submit a pull request

Development Setup

# Clone the repository
git clone https://github.com/AhEsmaeili79/oasist.git
cd oasist

# Create virtual environment
python -m venv venv
source venv/bin/activate  # or venv\Scripts\activate on Windows

# Install in development mode
pip install -e .

# Run tests
pytest

License

MIT License - See LICENSE file for details

Copyright (c) 2024 AH Esmaeili

Support

For issues or questions:

  • Check the Troubleshooting section
  • Review the OpenAPI schema URL accessibility
  • Verify all dependencies are installed
  • Enable debug logging for detailed error information

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

oasist-1.1.0.tar.gz (33.7 kB view details)

Uploaded Source

Built Distribution

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

oasist-1.1.0-py3-none-any.whl (18.2 kB view details)

Uploaded Python 3

File details

Details for the file oasist-1.1.0.tar.gz.

File metadata

  • Download URL: oasist-1.1.0.tar.gz
  • Upload date:
  • Size: 33.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.5

File hashes

Hashes for oasist-1.1.0.tar.gz
Algorithm Hash digest
SHA256 57822f5d7dd0c2a306593b03db4da6cc808c3b997ad664a083cf14ca791ab551
MD5 603182b7ac677f9781ecda61008d9d44
BLAKE2b-256 dfe6fa377691f1d636d5b18dd627a65155fb6535d607ab74d4c5550d491fdb73

See more details on using hashes here.

File details

Details for the file oasist-1.1.0-py3-none-any.whl.

File metadata

  • Download URL: oasist-1.1.0-py3-none-any.whl
  • Upload date:
  • Size: 18.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.5

File hashes

Hashes for oasist-1.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 6c0ffed5333678617d8c6100e65a478e2c3891bff3ec683752d30ac641e1cf6f
MD5 d0e22401d0439bdc4193c8a67dd2e5d5
BLAKE2b-256 f5a62fa3e4577a16c7ebfcd3ff996906d655b4534b13a1618bbbc679d0dd7f07

See more details on using hashes here.

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