CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-minos-microservice-networks

The networks core of the Minos Framework providing networking components for reactive microservices

Pending
Overview
Eval results
Files

specs.mddocs/

API Specification Services

Built-in services for generating OpenAPI and AsyncAPI specifications from decorated handlers. Provides automated API documentation and specification generation.

Capabilities

OpenAPI Service

Service for generating OpenAPI 3.0 specifications from REST endpoints.

class OpenAPIService:
    def __init__(self, config: Config): ...
    config: Config
    spec: dict
    endpoints: list[dict]
    @enroute.rest.command("/spec/openapi", "GET")
    async def generate_specification(self, request: Request) -> Response: ...

Usage Examples:

from minos.networks import OpenAPIService, enroute
from minos.common import Config

# Service with REST endpoints
class UserAPI:
    @enroute.rest.query("/users", method="GET")
    async def list_users(self, request) -> Response:
        return Response({"users": []})
    
    @enroute.rest.command("/users", method="POST")
    async def create_user(self, request) -> Response:
        return Response({"id": "123"}, status=201)

# Setup OpenAPI service
config = Config("config.yml")
openapi_service = OpenAPIService(config)

# The service automatically exposes /spec/openapi endpoint
# Access at: GET http://localhost:8080/spec/openapi

AsyncAPI Service

Service for generating AsyncAPI 2.3.0 specifications from broker events.

class AsyncAPIService:
    def __init__(self, config: Config): ...
    config: Config
    spec: dict
    @enroute.rest.command("/spec/asyncapi", "GET")
    async def generate_specification(self, request: Request) -> Response: ...
    def get_events(self) -> list[dict]: ...

Usage Examples:

from minos.networks import AsyncAPIService, enroute
from minos.common import Config

# Service with broker events
class UserEvents:
    @enroute.broker.event("user.created")
    async def handle_user_created(self, request) -> Response:
        return Response({"processed": True})
    
    @enroute.broker.event("user.updated")
    async def handle_user_updated(self, request) -> Response:
        return Response({"processed": True})

# Setup AsyncAPI service
config = Config("config.yml")
asyncapi_service = AsyncAPIService(config)

# The service automatically exposes /spec/asyncapi endpoint
# Access at: GET http://localhost:8080/spec/asyncapi

Advanced Usage

Complete API Documentation Setup

from minos.networks import (
    OpenAPIService, AsyncAPIService, HttpPort, 
    enroute, Request, Response
)
from minos.common import Config

class DocumentedAPI:
    # REST endpoints for OpenAPI
    @enroute.rest.query("/users", method="GET")
    async def list_users(self, request: Request) -> Response:
        """List all users"""
        return Response({"users": []})
    
    @enroute.rest.command("/users", method="POST") 
    async def create_user(self, request: Request) -> Response:
        """Create a new user"""
        user_data = await request.content()
        return Response({"id": "123", **user_data}, status=201)
    
    @enroute.rest.query("/users/{user_id}", method="GET")
    async def get_user(self, request: Request) -> Response:
        """Get user by ID"""
        params = await request.params()
        return Response({"id": params["user_id"], "name": "John"})
    
    # Broker events for AsyncAPI
    @enroute.broker.event("user.created")
    async def on_user_created(self, request: Request) -> Response:
        """Handle user creation events"""
        return Response({"processed": True})
    
    @enroute.broker.event("user.updated")
    async def on_user_updated(self, request: Request) -> Response:
        """Handle user update events"""
        return Response({"processed": True})
    
    @enroute.broker.command("user.validate")
    async def validate_user(self, request: Request) -> Response:
        """Validate user data"""
        return Response({"valid": True})

# Configuration
config = Config({
    "service": {
        "name": "user-service",
        "version": "1.0.0",
        "description": "User management microservice"
    }
})

# Setup specification services
openapi_service = OpenAPIService(config)
asyncapi_service = AsyncAPIService(config)

# Setup HTTP port
http_port = HttpPort._from_config(config)

# Start services
await http_port.start()

print("API running with auto-generated documentation:")
print("- OpenAPI spec: http://localhost:8080/spec/openapi")
print("- AsyncAPI spec: http://localhost:8080/spec/asyncapi")

Custom Specification Enhancement

class EnhancedOpenAPIService(OpenAPIService):
    def __init__(self, config: Config):
        super().__init__(config)
        
        # Enhance base specification
        self.spec.update({
            "info": {
                "title": config.service.name,
                "version": config.service.version,
                "description": config.service.description,
                "contact": {
                    "name": "API Support",
                    "email": "support@example.com"
                }
            },
            "servers": [
                {
                    "url": f"http://localhost:{config.service.port}",
                    "description": "Development server"
                },
                {
                    "url": f"https://api.example.com",
                    "description": "Production server"
                }
            ]
        })
    
    @enroute.rest.command("/spec/openapi", "GET")
    async def generate_specification(self, request: Request) -> Response:
        """Generate enhanced OpenAPI specification"""
        # Get base specification
        base_response = await super().generate_specification(request)
        base_spec = await base_response.content()
        
        # Add custom extensions
        base_spec["x-custom-version"] = "1.0"
        base_spec["x-generator"] = "minos-networks"
        
        # Add security schemes
        base_spec["components"] = {
            "securitySchemes": {
                "bearerAuth": {
                    "type": "http",
                    "scheme": "bearer",
                    "bearerFormat": "JWT"
                },
                "apiKey": {
                    "type": "apiKey",
                    "in": "header",
                    "name": "X-API-Key"
                }
            }
        }
        
        return Response(base_spec)

# Usage
enhanced_openapi = EnhancedOpenAPIService(config)

Specification Validation and Export

import json
import yaml
from pathlib import Path

class SpecificationManager:
    def __init__(self, config: Config):
        self.config = config
        self.openapi_service = OpenAPIService(config)
        self.asyncapi_service = AsyncAPIService(config)
    
    async def export_specifications(self, output_dir: str = "./specs"):
        """Export specifications to files"""
        output_path = Path(output_dir)
        output_path.mkdir(exist_ok=True)
        
        # Generate OpenAPI spec
        openapi_response = await self.openapi_service.generate_specification(None)
        openapi_spec = await openapi_response.content()
        
        # Generate AsyncAPI spec
        asyncapi_response = await self.asyncapi_service.generate_specification(None)
        asyncapi_spec = await asyncapi_response.content()
        
        # Export as JSON
        with open(output_path / "openapi.json", "w") as f:
            json.dump(openapi_spec, f, indent=2)
        
        with open(output_path / "asyncapi.json", "w") as f:
            json.dump(asyncapi_spec, f, indent=2)
        
        # Export as YAML
        with open(output_path / "openapi.yaml", "w") as f:
            yaml.dump(openapi_spec, f, default_flow_style=False)
        
        with open(output_path / "asyncapi.yaml", "w") as f:
            yaml.dump(asyncapi_spec, f, default_flow_style=False)
        
        print(f"Specifications exported to {output_path}")
    
    def validate_openapi_spec(self, spec: dict) -> bool:
        """Validate OpenAPI specification"""
        required_fields = ["openapi", "info", "paths"]
        return all(field in spec for field in required_fields)
    
    def validate_asyncapi_spec(self, spec: dict) -> bool:
        """Validate AsyncAPI specification"""
        required_fields = ["asyncapi", "info", "channels"]
        return all(field in spec for field in required_fields)

# Usage
spec_manager = SpecificationManager(config)

# Export specifications
await spec_manager.export_specifications("./api-docs")

# Validate specifications
openapi_response = await spec_manager.openapi_service.generate_specification(None)
openapi_spec = await openapi_response.content()
is_valid = spec_manager.validate_openapi_spec(openapi_spec)
print(f"OpenAPI spec valid: {is_valid}")

Integration with Documentation Tools

class DocumentationIntegration:
    def __init__(self, config: Config):
        self.config = config
        self.openapi_service = OpenAPIService(config)
        self.asyncapi_service = AsyncAPIService(config)
    
    @enroute.rest.query("/docs", method="GET")
    async def swagger_ui(self, request: Request) -> Response:
        """Serve Swagger UI for OpenAPI documentation"""
        swagger_html = f"""
        <!DOCTYPE html>
        <html>
        <head>
            <title>API Documentation</title>
            <link rel="stylesheet" type="text/css" href="https://unpkg.com/swagger-ui-dist@3.52.5/swagger-ui.css" />
        </head>
        <body>
            <div id="swagger-ui"></div>
            <script src="https://unpkg.com/swagger-ui-dist@3.52.5/swagger-ui-bundle.js"></script>
            <script>
                SwaggerUIBundle({{
                    url: '/spec/openapi',
                    dom_id: '#swagger-ui',
                    presets: [SwaggerUIBundle.presets.apis, SwaggerUIBundle.presets.standalone]
                }});
            </script>
        </body>
        </html>
        """
        return Response(swagger_html, content_type="text/html")
    
    @enroute.rest.query("/async-docs", method="GET")
    async def asyncapi_docs(self, request: Request) -> Response:
        """Serve AsyncAPI documentation"""
        asyncapi_html = f"""
        <!DOCTYPE html>
        <html>
        <head>
            <title>AsyncAPI Documentation</title>
        </head>
        <body>
            <div id="asyncapi"></div>
            <script src="https://unpkg.com/@asyncapi/web-component@1.0.0-next.39/lib/asyncapi-web-component.js" defer></script>
            <asyncapi-component
                schemaUrl="/spec/asyncapi"
                config='{{"show": {{"sidebar": true}}}}'
            ></asyncapi-component>
        </body>
        </html>
        """
        return Response(asyncapi_html, content_type="text/html")
    
    @enroute.rest.query("/", method="GET")
    async def api_index(self, request: Request) -> Response:
        """API documentation index page"""
        index_html = """
        <!DOCTYPE html>
        <html>
        <head>
            <title>API Documentation</title>
        </head>
        <body>
            <h1>API Documentation</h1>
            <ul>
                <li><a href="/docs">REST API (Swagger UI)</a></li>
                <li><a href="/async-docs">Async API Documentation</a></li>
                <li><a href="/spec/openapi">OpenAPI Specification (JSON)</a></li>
                <li><a href="/spec/asyncapi">AsyncAPI Specification (JSON)</a></li>
            </ul>
        </body>
        </html>
        """
        return Response(index_html, content_type="text/html")

# Usage - automatically provides documentation endpoints
doc_integration = DocumentationIntegration(config)

# Access documentation at:
# http://localhost:8080/          - Documentation index
# http://localhost:8080/docs      - Swagger UI
# http://localhost:8080/async-docs - AsyncAPI docs

Install with Tessl CLI

npx tessl i tessl/pypi-minos-microservice-networks

docs

brokers.md

decorators.md

discovery.md

http.md

index.md

requests.md

routers.md

scheduling.md

specs.md

system-utils.md

tile.json