#!/usr/bin/env python3 """ Generate OpenAPI 3.0 specification from architecture information. Creates a comprehensive API specification for the designed endpoints. """ import sys import json from typing import Dict, List, Any def generate_openapi_spec(api_info: Dict[str, Any]) -> Dict[str, Any]: """Generate OpenAPI 3.0 specification.""" system_name = api_info.get('system_name', 'API') version = api_info.get('version', '1.0.0') description = api_info.get('description', 'API for ' + system_name) base_url = api_info.get('base_url', 'https://api.example.com') spec = { "openapi": "3.0.3", "info": { "title": f"{system_name} API", "description": description, "version": version, "contact": { "name": api_info.get('contact_name', 'API Team'), "email": api_info.get('contact_email', 'api@example.com') } }, "servers": [ { "url": base_url, "description": api_info.get('server_description', 'Production server') } ], "paths": {}, "components": { "schemas": {}, "securitySchemes": {}, "responses": {} }, "tags": [] } # Add security schemes auth_type = api_info.get('authentication', 'bearer') if auth_type == 'bearer' or auth_type == 'jwt': spec['components']['securitySchemes']['bearerAuth'] = { "type": "http", "scheme": "bearer", "bearerFormat": "JWT" } spec['security'] = [{"bearerAuth": []}] elif auth_type == 'apikey': spec['components']['securitySchemes']['apiKey'] = { "type": "apiKey", "in": "header", "name": "X-API-Key" } spec['security'] = [{"apiKey": []}] # Add common schemas spec['components']['schemas']['Error'] = { "type": "object", "properties": { "error": { "type": "string", "description": "Error message" }, "code": { "type": "string", "description": "Error code" } }, "required": ["error"] } # Add common responses spec['components']['responses']['UnauthorizedError'] = { "description": "Authentication information is missing or invalid", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } spec['components']['responses']['NotFoundError'] = { "description": "The specified resource was not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } # Add tags tags = api_info.get('tags', []) for tag in tags: spec['tags'].append({ "name": tag.get('name', 'default'), "description": tag.get('description', '') }) # Add schemas schemas = api_info.get('schemas', {}) for schema_name, schema_def in schemas.items(): spec['components']['schemas'][schema_name] = schema_def # Add endpoints endpoints = api_info.get('endpoints', []) for endpoint in endpoints: path = endpoint.get('path', '/') method = endpoint.get('method', 'get').lower() if path not in spec['paths']: spec['paths'][path] = {} operation = { "summary": endpoint.get('summary', ''), "description": endpoint.get('description', ''), "operationId": endpoint.get('operation_id', method + path.replace('/', '_')), "tags": endpoint.get('tags', ['default']), "responses": {} } # Add parameters parameters = endpoint.get('parameters', []) if parameters: operation['parameters'] = parameters # Add request body request_body = endpoint.get('request_body', None) if request_body: operation['requestBody'] = request_body # Add responses responses = endpoint.get('responses', {}) if responses: operation['responses'] = responses else: # Default responses operation['responses'] = { "200": { "description": "Successful operation", "content": { "application/json": { "schema": { "type": "object" } } } }, "401": { "$ref": "#/components/responses/UnauthorizedError" }, "404": { "$ref": "#/components/responses/NotFoundError" } } spec['paths'][path][method] = operation return spec def generate_default_crud_api(resource_name: str) -> Dict[str, Any]: """Generate a default CRUD API specification for a resource.""" resource_lower = resource_name.lower() resource_title = resource_name.title() api_info = { "system_name": f"{resource_title} Management", "version": "1.0.0", "description": f"API for managing {resource_lower} resources", "base_url": "https://api.example.com/v1", "authentication": "bearer", "tags": [ { "name": resource_lower, "description": f"{resource_title} operations" } ], "schemas": { resource_title: { "type": "object", "properties": { "id": { "type": "string", "format": "uuid", "description": f"{resource_title} ID" }, "name": { "type": "string", "description": f"{resource_title} name" }, "createdAt": { "type": "string", "format": "date-time", "description": "Creation timestamp" }, "updatedAt": { "type": "string", "format": "date-time", "description": "Last update timestamp" } }, "required": ["id", "name"] }, f"{resource_title}Input": { "type": "object", "properties": { "name": { "type": "string", "description": f"{resource_title} name" } }, "required": ["name"] } }, "endpoints": [ { "path": f"/{resource_lower}s", "method": "get", "summary": f"List all {resource_lower}s", "description": f"Retrieve a list of {resource_lower}s with pagination", "operation_id": f"list{resource_title}s", "tags": [resource_lower], "parameters": [ { "name": "page", "in": "query", "description": "Page number", "schema": {"type": "integer", "default": 1} }, { "name": "limit", "in": "query", "description": "Items per page", "schema": {"type": "integer", "default": 20} } ], "responses": { "200": { "description": "Successful operation", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": f"#/components/schemas/{resource_title}" } }, "total": {"type": "integer"}, "page": {"type": "integer"}, "limit": {"type": "integer"} } } } } } } }, { "path": f"/{resource_lower}s", "method": "post", "summary": f"Create a new {resource_lower}", "description": f"Create a new {resource_lower} resource", "operation_id": f"create{resource_title}", "tags": [resource_lower], "request_body": { "required": True, "content": { "application/json": { "schema": { "$ref": f"#/components/schemas/{resource_title}Input" } } } }, "responses": { "201": { "description": "Created successfully", "content": { "application/json": { "schema": { "$ref": f"#/components/schemas/{resource_title}" } } } } } }, { "path": f"/{resource_lower}s/{{id}}", "method": "get", "summary": f"Get a {resource_lower} by ID", "description": f"Retrieve a specific {resource_lower} by its ID", "operation_id": f"get{resource_title}", "tags": [resource_lower], "parameters": [ { "name": "id", "in": "path", "required": True, "description": f"{resource_title} ID", "schema": {"type": "string", "format": "uuid"} } ], "responses": { "200": { "description": "Successful operation", "content": { "application/json": { "schema": { "$ref": f"#/components/schemas/{resource_title}" } } } } } }, { "path": f"/{resource_lower}s/{{id}}", "method": "put", "summary": f"Update a {resource_lower}", "description": f"Update an existing {resource_lower} resource", "operation_id": f"update{resource_title}", "tags": [resource_lower], "parameters": [ { "name": "id", "in": "path", "required": True, "description": f"{resource_title} ID", "schema": {"type": "string", "format": "uuid"} } ], "request_body": { "required": True, "content": { "application/json": { "schema": { "$ref": f"#/components/schemas/{resource_title}Input" } } } }, "responses": { "200": { "description": "Updated successfully", "content": { "application/json": { "schema": { "$ref": f"#/components/schemas/{resource_title}" } } } } } }, { "path": f"/{resource_lower}s/{{id}}", "method": "delete", "summary": f"Delete a {resource_lower}", "description": f"Delete a {resource_lower} resource", "operation_id": f"delete{resource_title}", "tags": [resource_lower], "parameters": [ { "name": "id", "in": "path", "required": True, "description": f"{resource_title} ID", "schema": {"type": "string", "format": "uuid"} } ], "responses": { "204": { "description": "Deleted successfully" } } } ] } return generate_openapi_spec(api_info) def main(): """Main entry point.""" if len(sys.argv) < 2: print("Usage: python generate_openapi.py ") print("\nExamples:") print(" python generate_openapi.py 'User' # Generate default CRUD API") print(" python generate_openapi.py '{...}' # Generate from JSON config") sys.exit(1) input_data = sys.argv[1] # Try to parse as JSON first try: config = json.loads(input_data) spec = generate_openapi_spec(config) except json.JSONDecodeError: # Treat as resource name for default CRUD API spec = generate_default_crud_api(input_data) # Output OpenAPI spec print(json.dumps(spec, indent=2)) if __name__ == "__main__": main()