FastOpenAPI

repository·master·Indexed 19 days ago

https://github.com/mr-fatalyst/fastopenapi

A library for generating and integrating OpenAPI schemas using Pydantic v2 across various Python web frameworks, including AioHttp, Django, Falcon, Flask, Quart, Sanic, Starlette, and Tornado. It provides a developer experience similar to FastAPI with broader framework support, offering automatic OpenAPI documentation via Swagger UI and ReDoc UI.

Tokens
116.4K
Snippets
302
Records
371
Agent score
63%

What's inside fastopenapi

  1. What is FastOpenAPI?

    master

    FastOpenAPI is a library designed to bring a FastAPI-style developer experience to various Python web frameworks. It enables automatic OpenAPI schema generation, interactive documentation (Swagger UI and ReDoc), request validation via Pydantic, and response serialization, all while remaining framework-agnostic.

    Key capabilities include:

    • Automatic OpenAPI generation: Derived from your route definitions.
    • Interactive Docs: Access via Swagger UI or ReDoc.
    • Pydantic v2 Integration: For robust validation and JSON Schema generation.
    • Multi-Framework Support: Works with AIOHTTP, Django, Falcon, Flask, Quart, Sanic, Starlette, and Tornado.
  2. Select a framework-specific router

    master

    FastOpenAPI provides specialized router classes for various web frameworks. Choose the router that matches your framework and whether you are using synchronous or asynchronous patterns:

    • aiohttp: AioHttpRouter (async)
    • Django: DjangoRouter (sync) or DjangoAsyncRouter (async)
    • Falcon: FalconRouter (sync) or FalconAsyncRouter (async)
    • Flask: FlaskRouter (sync)
    • Quart: QuartRouter (async)
    • Sanic: SanicRouter (async)
    • Starlette: StarletteRouter (async)
    • Tornado: TornadoRouter (async/sync)
    • Generic/Other: StarletteRouter is often used for general ASGI-compatible apps.
  3. What is FastOpenAPI and when to use it

    master

    FastOpenAPI is a library designed to add OpenAPI/Swagger documentation and request/response validation to existing web frameworks.

    Key distinction from FastAPI:

    • FastAPI is a full web framework with native OpenAPI integration.
    • FastOpenAPI is a library you add to existing frameworks (like Flask, AIOHTTP, etc.) to provide similar developer experiences without switching frameworks.

    When to use FastOpenAPI:

    • You have an existing application in another framework.
    • You need to support multiple different frameworks with a single toolset.
  4. Use Pydantic Models for Validation and Serialization

    master

    FastOpenAPI leverages Pydantic for three core tasks:

    1. Request Body Validation: Ensuring incoming data matches the expected schema.
    2. Response Serialization: Converting Python objects/dicts into JSON.
    3. Schema Generation: Automatically creating JSON Schemas for the OpenAPI document.

    When using response_model in a decorator, FastOpenAPI validates the return value of your function against that model. If the response is invalid, it raises an InternalServerError (500).

    from pydantic import BaseModel, Field
    
    class Item(BaseModel):
        name: str = Field(..., description="Item name")
        price: float = Field(..., gt=0, description="Price must be positive")
        description: str | None = None
    
    @router.post("/items", response_model=Item)
    def create_item(item: Item = Body(...)):
        # item is already validated
        return item
  5. Manage route priority and order

    master

    Routes are matched in the order they are defined. Always define more specific routes (e.g., /items/featured) before generic routes with path parameters (e.g., /items/{item_id}) to prevent the generic route from intercepting requests intended for the specific one.

    # Correct order
    @router.get("/items/featured")
    def get_featured():
        return {"items": ["featured1"]}
    
    @router.get("/items/{item_id}")
    def get_item(item_id: int):
        return {"item_id": item_id}
  6. How FastOpenAPI works

    master

    FastOpenAPI acts as a bridge between your existing web framework (like Flask or Django) and OpenAPI documentation. It registers routes with your framework, validates incoming requests against Pydantic models, generates the OpenAPI schema, and provides interactive documentation via Swagger UI or ReDoc.

    The Request Flow:

    1. Route Definition: You define routes using FastOpenAPI decorators.
    2. Registration: FastOpenAPI registers these routes with your underlying framework.
    3. Request Handling: When a request arrives, FastOpenAPI extracts parameters, validates them against Pydantic models, calls your endpoint, and then validates/serializes the response.
    4. Schema Generation: The OpenAPI schema is generated from your route definitions.
    5. Documentation: Documentation UIs (Swagger UI, ReDoc) consume the schema to create interactive docs.
  7. Use FastOpenAPI parameters for validation

    master

    FastOpenAPI parameters extend Pydantic's FieldInfo. You can use them to define where parameters are located (Query, Path, Header, Cookie, Body) and apply validation constraints.

    Parameter Hierarchy:

    • BaseParam (extends FieldInfo)
      • Param (adds in_ source)
        • Query (in_ = QUERY)
        • Path (in_ = PATH)
        • Header (in_ = HEADER, supports convert_underscores)
        • Cookie (in_ = COOKIE)
      • Body (adds body-specific logic)
        • Form (in_ = FORM)
        • File (in_ = FILE)
  8. Understand the FastOpenAPI Request Processing Flow

    master

    FastOpenAPI follows a structured pipeline to process HTTP requests. When a request arrives, the framework performs the following steps:

    1. Routing: The framework matches the request to a registered handler.
    2. Enveloping: A RequestEnvelope is created to wrap the framework-specific request.
    3. Extraction: An Extractor pulls framework-agnostic RequestData from the envelope.
    4. Parameter Resolution: The ParameterResolver uses a DependencyResolver to:
      • Resolve Depends() parameters.
      • Extract parameters from RequestData (path, query, etc.).
      • Create and validate a dynamic Pydantic model.
    5. Endpoint Execution: The endpoint is called with the validated kwargs.
    6. Response Validation: If a response_model is provided, the result is validated.
    7. Serialization: The ResponseBuilder serializes the result to JSON.
    8. Finalization: The framework-specific response is built and returned to the client.
  9. Validate nested models and collections

    master

    Pydantic allows for complex, deeply nested data structures by using other BaseModel classes as type hints.

    from pydantic import BaseModel, EmailStr
    from datetime import datetime
    
    class Address(BaseModel):
        street: str
        city: str
        postal_code: str
        country: str = "USA"
    
    class User(BaseModel):
        name: str
        email: EmailStr
        address: Address  # Nested model
    
    class Order(BaseModel):
        order_id: int
        items: list[Address]  # List of nested models
  10. How dependency injection works in FastOpenAPI

    master

    FastOpenAPI includes a FastAPI-like dependency injection (DI) system. It supports:

    • Depends(func): For regular dependencies.
    • Security(func, scopes=[...]): For security-related dependencies.
    • SecurityScopes: For injecting scopes.

    DI Features:

    • Recursive resolution.
    • Request-scoped caching.
    • Circular dependency detection.
    • Async dependencies.
    • Generator (yield) dependencies with automatic cleanup.

    Note: FastOpenAPI does not provide background tasks or middleware injection; you should use your underlying web framework's native mechanisms for those features.

  11. How Request Data Extractors work

    master

    Request Data Extractors are responsible for converting framework-specific request objects into a RequestData container.

    Implementation Details:

    • Sync vs Async: Methods like _get_path_params, _get_query_params, _get_headers, and _get_cookies are synchronous. Only _get_body, _get_form_data, and _get_files are implemented as asynchronous methods in the BaseAsyncRequestDataExtractor.
    • Framework Specifics: Each framework (e.g., Starlette, Flask) provides its own implementation (e.g., StarletteRequestDataExtractor).
    • Input: The _get_* methods receive the raw framework request object, not the RequestEnvelope.
    class BaseAsyncRequestDataExtractor(BaseRequestDataExtractor, ABC):
        """Base async extractor — overrides only body/form/files as async"""
    
        @classmethod
        @abstractmethod
        async def _get_body(cls, request: Any) -> bytes | str | dict: ...
    
        @classmethod
        @abstractmethod
        async def _get_form_data(cls, request: Any) -> dict: ...
    
        @classmethod
        @abstractmethod
        async def _get_files(cls, request: Any) -> dict: ...
    
        @classmethod
        async def extract_request_data(cls, env: RequestEnvelope) -> RequestData:
            request = env.request
            return RequestData(
                path_params=env.path_params or cls._get_path_params(request),
                query_params=cls._get_query_params(request),          # sync
                headers=cls._normalize_headers(cls._get_headers(request)),  # sync
                cookies=cls._get_cookies(request),                    # sync
                body=await cls._get_body(request),                    # async
                form_data=await cls._get_form_data(request),          # async
                files=await cls._get_files(request),                  # async
            )
  12. Interpret benchmark performance overheads

    master

    When analyzing the benchmark results, use the following mental model to understand the performance impact of different layers:

    • Pure Performance: Represents the raw framework overhead (routing, parsing, serialization). This is the 100% baseline.
    • Validators Overhead: The cost of adding Pydantic validation for both input (request) and output (response) models. Typically adds 5-15% overhead.
    • FastOpenAPI Overhead: The cost of adding automatic OpenAPI documentation generation (router proxy layer, schema extraction, etc.). Typically adds 8-20% overhead on top of the Pure implementation.
    • FastAPI Comparison: Used to determine if FastOpenAPI is competitive with the industry standard for async frameworks with built-in validation and docs.