{"id":31646543,"url":"https://github.com/ahesmaeili79/oasist","last_synced_at":"2025-10-24T23:03:12.608Z","repository":{"id":318205900,"uuid":"1070335428","full_name":"AhEsmaeili79/oasist","owner":"AhEsmaeili79","description":"🎯 Stop writing API clients manually! Generate type-safe Python clients from OpenAPI schemas with a beautiful CLI. Works with any API - FastAPI, Django, Flask, and more.","archived":false,"fork":false,"pushed_at":"2025-10-06T21:09:31.000Z","size":58,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-10-07T05:58:13.374Z","etag":null,"topics":["api-client","code-generator","django","django-rest-framework","drf-spectacular","drf-yasg","fastapi","openapi","openapi-docs","openapi-generator","openapi-python-client","openapi-spec","python","python-swagger-generator","swagger","swagger-generator","type-safe"],"latest_commit_sha":null,"homepage":"https://pypi.org/project/oasist/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/AhEsmaeili79.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-10-05T18:12:12.000Z","updated_at":"2025-10-06T21:09:34.000Z","dependencies_parsed_at":"2025-10-05T20:41:18.985Z","dependency_job_id":null,"html_url":"https://github.com/AhEsmaeili79/oasist","commit_stats":null,"previous_names":["ahesmaeili79/oasist"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/AhEsmaeili79/oasist","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AhEsmaeili79%2Foasist","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AhEsmaeili79%2Foasist/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AhEsmaeili79%2Foasist/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AhEsmaeili79%2Foasist/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/AhEsmaeili79","download_url":"https://codeload.github.com/AhEsmaeili79/oasist/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AhEsmaeili79%2Foasist/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278924143,"owners_count":26069400,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-08T02:00:06.501Z","response_time":56,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api-client","code-generator","django","django-rest-framework","drf-spectacular","drf-yasg","fastapi","openapi","openapi-docs","openapi-generator","openapi-python-client","openapi-spec","python","python-swagger-generator","swagger","swagger-generator","type-safe"],"created_at":"2025-10-07T05:54:13.172Z","updated_at":"2025-10-24T23:03:12.590Z","avatar_url":"https://github.com/AhEsmaeili79.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# OASist Client Generator\n\nGenerate type-safe Python clients from OpenAPI schemas with a beautiful CLI interface. Supports both JSON and YAML schemas with Orval-inspired configuration.\n\nBuilt on top of **[openapi-python-client](https://github.com/openapi-generators/openapi-python-client)** with enhanced features and developer experience.\n\n## Features\n\n- 🚀 Clean, modular Python package with rich CLI interface\n- 📦 Generate type-safe Python clients from OpenAPI specs (JSON/YAML)\n- ✨ **Automatic code formatting with Black** (optional, enabled by default)\n- 🔄 Schema sanitization and validation with security fixes\n- 🎯 Orval-inspired configuration format with environment variable support\n- 🏗️ Built with design patterns (Strategy, Command, Dataclass)\n- ⚡ Automatic base URL detection and post-hook management\n- 🎨 Beautiful terminal UI with progress indicators\n- 🔒 Path traversal protection and input validation\n- 🔁 Automatic retry logic for common failures\n\n## Installation\n\n```bash\n# Install from PyPI\npip install oasist\n\n# Install with Black formatting support (recommended)\npip install oasist[formatting]\n\n# Or install Black separately\npip install black\n```\n\n## Quick Start\n\n```bash\n# List all configured services\noasist list\n\n# Generate a specific client\noasist generate user\n\n# Generate all clients\noasist generate-all\n\n# Show service details\noasist info user\n\n# Force regenerate existing client\noasist generate user --force\n\n# Use custom config file\noasist -c production.json generate user\n\n# Enable verbose/debug logging\noasist -v generate user\n```\n\n## Configuration\n\nThe 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.\n\n### Environment Variable Substitution\n\nOASist supports environment variable substitution in configuration files using the `${VAR}` or `${VAR:default}` syntax:\n\n- `${VAR}` - Replace with environment variable value (warns if not found)\n- `${VAR:default}` - Replace with environment variable value or use default if not found\n\nExample:\n```json\n{\n  \"projects\": {\n    \"api\": {\n      \"input\": {\n        \"target\": \"${API_SCHEMA_URL:http://localhost:8000/openapi.json}\"\n      },\n      \"output\": {\n        \"base_url\": \"${API_BASE_URL}\",\n        \"dir\": \"api_client\"\n      }\n    }\n  }\n}\n```\n\nCreate a `.env` file in your project root:\n```\nAPI_SCHEMA_URL=https://api.production.com/openapi.json\nAPI_BASE_URL=https://api.production.com\nAPI_TOKEN=your_secret_token_here\n```\n\n### Custom Headers\n\nYou can specify custom headers for schema fetch requests, which is useful for authenticated endpoints:\n\n```json\n{\n  \"projects\": {\n    \"protected_api\": {\n      \"input\": {\n        \"target\": \"https://api.example.com/openapi.json\",\n        \"headers\": {\n          \"Authorization\": \"Bearer ${API_TOKEN}\",\n          \"X-Custom-Header\": \"custom-value\"\n        }\n      },\n      \"output\": {\n        \"dir\": \"protected_api_client\"\n      }\n    }\n  }\n}\n```\n\n### Automatic Code Formatting with Black\n\nOASist automatically formats generated Python code using **Black** (if installed). This ensures clean, consistent code style across all generated clients.\n\n**Features:**\n- ✅ Enabled by default for all projects\n- ✅ Gracefully skips if Black is not installed (with helpful message)\n- ✅ Can be disabled per-project via configuration\n- ✅ Runs after successful client generation\n- ✅ Uses Black's default configuration (88-character line length)\n\n**Configuration:**\n\n```json\n{\n  \"projects\": {\n    \"formatted_api\": {\n      \"input\": {\n        \"target\": \"https://api.example.com/openapi.json\"\n      },\n      \"output\": {\n        \"dir\": \"formatted_client\",\n        \"format_with_black\": true  // Default: true\n      }\n    },\n    \"unformatted_api\": {\n      \"input\": {\n        \"target\": \"https://api.example.com/openapi.json\"\n      },\n      \"output\": {\n        \"dir\": \"unformatted_client\",\n        \"format_with_black\": false  // Disable formatting\n      }\n    }\n  }\n}\n```\n\n**Installing Black:**\n\n```bash\n# Install OASist with formatting support\npip install oasist[formatting]\n\n# Or install Black separately\npip install black\n```\n\n**What happens if Black is not installed?**\n- OASist will log a warning message\n- Generation will continue successfully\n- Code will be generated but not formatted\n- You'll see: \"Black is not installed. Skipping code formatting.\"\n\n### Basic Configuration\n\nCreate `oasist_config.json` in your project root:\n\n```json\n{\n  \"output_dir\": \"./test\",\n  \"projects\": {\n    \"user_service\": {\n      \"input\": {\n        \"target\": \"http://localhost:8001/openapi.json\",\n        \"prefer_json\": true\n      },\n      \"output\": {\n        \"dir\": \"user_service\",\n        \"name\": \"User Service\",\n        \"base_url\": \"http://localhost:8001\",\n        \"package_name\": \"user_service\",\n        \"format_with_black\": true\n      }\n    },\n    \"test\": {\n      \"input\": {\n        \"target\": \"${TEST_SCHEMA_URL}\",\n        \"prefer_json\": true,\n        \"_comment\": \"Optional headers for the schema fetch request\",\n        \"headers\": {\n          \"Authorization\": \"Bearer ${API_TOKEN}\",\n          \"X-API-Key\": \"${API_KEY:default_key}\"\n        }\n      },\n      \"output\": {\n        \"dir\": \"test\",\n        \"name\": \"Test\",\n        \"base_url\": \"${TEST_BASE_URL}\",\n        \"package_name\": \"test\",\n        \"format_with_black\": true,\n        \"_comment\": \"Set format_with_black to false to disable automatic code formatting\"\n      }\n    },\n    \"local_yaml\": {\n      \"input\": {\n        \"target\": \"http://localhost:8004/api/schema/\"\n      },\n      \"output\": {\n        \"dir\": \"local_yaml_client\",\n        \"name\": \"Local YAML API\",\n        \"base_url\": \"http://localhost:8004\",\n        \"package_name\": \"local_yaml_client\",\n        \"format_with_black\": false\n      }\n    }\n  }\n}\n```\n\n \n\n### Configuration Parameters\n\n#### Global Parameters\n| Parameter | Required | Description |\n|-----------|----------|-------------|\n| `output_dir` | No | Base directory for all generated clients (default: \"./clients\") |\n| `projects` | Yes | Object containing project configurations keyed by project name |\n\n#### Project Input Parameters\n| Parameter | Required | Description |\n|-----------|----------|-------------|\n| `target` | Yes | URL to OpenAPI schema endpoint |\n| `prefer_json` | No | If true, prefers JSON format over YAML |\n| `params` | No | Query parameters for schema fetch requests |\n| `headers` | No | Custom HTTP headers for schema fetch requests |\n\n#### Project Output Parameters\n| Parameter | Required | Description |\n|-----------|----------|-------------|\n| `dir` | Yes | Directory name for generated client |\n| `name` | Yes | Human-readable service name |\n| `base_url` | No | Service base URL (auto-detected if not provided) |\n| `package_name` | No | Python package name (auto-generated if not provided) |\n| `format_with_black` | No | Enable Black code formatting (default: true) |\n\n## Usage in Code\n\n```python\n# Import the generated client\nfrom clients.user_service.user_service_client import Client\n\n# Initialize client\nclient = Client(base_url=\"http://192.168.100.11:8011\")\n\n# Use the client\nresponse = client.users.list_users()\nuser = client.users.get_user(user_id=123)\n```\n\n## All Commands\n\n### Global Options\n\n```bash\n# Use custom configuration file\noasist -c custom_config.json \u003ccommand\u003e\noasist --config custom_config.json \u003ccommand\u003e\n\n# Enable verbose/debug logging\noasist -v \u003ccommand\u003e\noasist --verbose \u003ccommand\u003e\n\n# Combine options\noasist -v -c prod.json generate-all\n```\n\n### Basic Commands\n\n```bash\n# Show general help\noasist --help\noasist help\n\n# Show command-specific help\noasist help generate\noasist generate --help\n\n# Show version information\noasist --version\n\n# List all services and their generation status\noasist list\n\n# Show detailed information about a service\noasist info \u003cservice_name\u003e\n```\n\n### Generation Commands\n\n```bash\n# Generate client for a specific service\noasist generate \u003cservice_name\u003e\n\n# Force regenerate (overwrite existing)\noasist generate \u003cservice_name\u003e --force\n\n# Generate clients for all configured services\noasist generate-all\n\n# Generate all with force overwrite\noasist generate-all --force\n```\n\n## Project Structure\n\n```\nOASist/\n├── oasist/                 # Main package\n│   ├── __init__.py         # Package exports and version\n│   ├── oasist.py          # Single-file generator implementation\n│   └── __pycache__/       # Python cache files\n├── dist/                   # Distribution files (wheels, tarballs)\n├── venv/                   # Virtual environment\n├── oasist_config.json      # Configuration file\n├── example.oasist_config.json  # Example configuration\n├── pyproject.toml          # Project configuration\n├── requirements.txt        # Dependencies\n├── README.md              # This file\n└── test/                  # Generated clients directory (configurable)\n    ├── user_service/      # Generated client example\n    │   ├── pyproject.toml\n    │   └── user_service_client/\n    │       ├── __init__.py\n    │       ├── client.py\n    │       ├── api/\n    │       ├── models/\n    │       └── types.py\n    └── [other_services]/  # Additional generated clients\n```\n\n## Requirements\n\n### Core Dependencies\n- Python 3.8+\n- openapi-python-client \u003e= 0.26.1\n- requests \u003e= 2.31.0\n- pyyaml \u003e= 6.0.1\n- rich \u003e= 13.7.0\n- python-dotenv \u003e= 1.0.1\n\n### Optional Dependencies\n- black \u003e= 23.0.0 (for automatic code formatting)\n\nInstall with formatting support:\n```bash\npip install oasist[formatting]\n```\n\n## Troubleshooting\n\n### Schema URL not accessible\nEnsure the service is running and the schema endpoint is correct:\n```bash\ncurl http://192.168.100.11:8011/api/schema/\n```\n\n### Permission errors\nEnsure write permissions for the clients directory:\n```bash\nchmod -R u+w clients/\n```\n\n### Client generation fails\nCheck if openapi-python-client is installed:\n```bash\npip install --upgrade openapi-python-client\n```\n\nEnable debug logging in code:\n```python\nlogging.basicConfig(level=logging.DEBUG)\n```\n\n### Black formatting not working\nCheck if Black is installed:\n```bash\nblack --version\n```\n\nInstall Black if needed:\n```bash\npip install black\n# Or\npip install oasist[formatting]\n```\n\nDisable formatting if not needed:\n```json\n{\n  \"output\": {\n    \"format_with_black\": false\n  }\n}\n```\n\n## Design Patterns Used\n\nOASist uses several design patterns to ensure maintainability and extensibility:\n\n- **Strategy Pattern**: `SchemaParser` protocol for pluggable JSON/YAML parsing\n- **Command Pattern**: CLI commands encapsulate different operations (list, generate, info)\n- **Dataclass Pattern**: Type-safe `ServiceConfig` with validation\n- **Context Manager**: Temporary file management with automatic cleanup\n- **Template Method**: Generator execution with customizable hooks\n\n### Why the Patterns?\n\nWhile this adds some code complexity, the benefits are:\n\n✅ **Easy to extend** - Add new parsers, commands, or validators without touching existing code  \n✅ **Type-safe** - Dataclasses provide validation and IDE autocomplete  \n✅ **Testable** - Each component can be tested independently  \n✅ **Maintainable** - Clear separation of concerns makes debugging easier  \n\nFor **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.\n\n## Django Integration (Optional)\n\nTo use with Django management commands:\n\n```python\n# In your Django management command\nfrom oasist import ClientGenerator, ServiceConfig\n\ngenerator = ClientGenerator(output_base=Path(\"./clients\"))\ngenerator.add_service(\"user\", ServiceConfig(...))\ngenerator.generate(\"user\")\n```\n\n## Advanced Usage\n\n### Programmatic Usage\n\n```python\nfrom oasist import ClientGenerator, ServiceConfig\nfrom pathlib import Path\n\n# Create generator with custom output directory\ngenerator = ClientGenerator(output_base=Path(\"./my_clients\"))\n\n# Add services\ngenerator.add_service(\"api\", ServiceConfig(\n    name=\"API Service\",\n    schema_url=\"https://api.example.com/openapi.json\",\n    output_dir=\"api_client\",\n    format_with_black=True  # Enable Black formatting\n))\n\n# Generate\ngenerator.generate(\"api\", force=True)\n\n# Or generate all\ngenerator.generate_all(force=True)\n\n# Note: You can also modify the OUTPUT_DIR constant at the top of the file\n# for persistent changes instead of passing output_base parameter\n```\n\n### Custom Base URL and Formatting Options\n\n```python\ngenerator.add_service(\"prod\", ServiceConfig(\n    name=\"Production API\",\n    schema_url=\"https://api.example.com/openapi.json\",\n    output_dir=\"prod_client\",\n    base_url=\"https://api.example.com\",  # Custom base URL\n    format_with_black=True  # Enable automatic Black formatting\n))\n\n# Disable formatting for specific service\ngenerator.add_service(\"legacy\", ServiceConfig(\n    name=\"Legacy API\",\n    schema_url=\"https://legacy.example.com/openapi.json\",\n    output_dir=\"legacy_client\",\n    format_with_black=False  # Disable formatting for this service\n))\n```\n\n## Examples\n\n### Example 1: Generate User Service Client\n\n```bash\n$ oasist generate user_service\nINFO: ✓ Generated client: user_service → test/user_service\n```\n\n### Example 2: List All Services\n\n```bash\n$ oasist list\n\n📋 Configured Services:\n  ○ user_service        User Service                  http://localhost:8001/openapi.json\n  ○ communication_service Communication Service       http://localhost:8002/openapi.json\n  ○ local_yaml          Local YAML API                http://localhost:8004/api/schema/\n```\n\n### Example 3: Service Information\n\n```bash\n$ oasist info user_service\n\n📦 Service: user_service\n   Name:        User Service\n   Schema URL:  http://localhost:8001/openapi.json\n   Output:      test/user_service\n   Status:      Not generated\n```\n\n## Contributing\n\nContributions are welcome! To extend or modify:\n\n1. Fork the repository\n2. Create a feature branch\n3. Make your changes with appropriate tests\n4. Submit a pull request\n\n### Development Setup\n\n```bash\n# Clone the repository\ngit clone https://github.com/AhEsmaeili79/oasist.git\ncd oasist\n\n# Create virtual environment\npython -m venv venv\nsource venv/bin/activate  # or venv\\Scripts\\activate on Windows\n\n# Install in development mode\npip install -e .\n\n# Run tests\npytest\n```\n\n## License\n\nMIT License - See [LICENSE](LICENSE) file for details\n\nCopyright (c) 2024 AH Esmaeili\n\n## Support\n\nFor issues or questions:\n- Check the Troubleshooting section\n- Review the OpenAPI schema URL accessibility\n- Verify all dependencies are installed\n- Enable debug logging for detailed error information\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fahesmaeili79%2Foasist","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fahesmaeili79%2Foasist","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fahesmaeili79%2Foasist/lists"}