Flaxon 0.3.0 and Teloce-Py 0.3.0 are available on PyPI. Release instructions are maintained on this site; source links identify the framework snapshot. Check version and upgrade guidance.

Framework source · Markdown

OpenAPI, Swagger UI, and ReDoc

Flaxon generates an OpenAPI 3.1 document from the routes already registered on your application. The generator reads path converters, endpoint annotations, native Flaxon schemas, optional Pydantic models, query declarations, docstrings, and route metadata. You do not maintain a second list of routes.

Enable automatic documentation

Pass openapi=True when creating the application:

from flaxon import Flaxon

app = Flaxon("catalog", openapi=True)

This registers:

URL Purpose
/openapi.json Generated OpenAPI 3.1 document
/docs Interactive Swagger UI with Try it out
/redoc ReDoc reference browser

The feature is opt-in. An application that does not pass openapi=True does not expose documentation routes.

Set application metadata directly in the constructor:

app = Flaxon(
    "catalog",
    openapi={
        "title": "Catalog API",
        "version": "2026.1",
        "description": "Inventory and ordering API.",
        "docs_url": "/api/docs",
        "redoc_url": "/api/reference",
        "openapi_url": "/api/openapi.json",
    },
)

The equivalent explicit form is useful when configuration is loaded later:

app = Flaxon("catalog")
app.enable_openapi(
    title="Catalog API",
    version="2026.1",
    openapi_url="/api/openapi.json",
    docs_url="/api/docs",
    redoc_url="/api/reference",
)

Typed routes and query parameters

Path converters and Query declarations become OpenAPI parameters and are also coerced and validated at runtime:

from flaxon import Query


@app.get(
    "/products/<int:product_id>",
    summary="Get a product",
    tags=["products"],
    operation_id="get_product",
)
async def get_product(
    product_id: int,
    page: int = Query(1, ge=1, description="One-based result page"),
    search: str = Query("", max_length=120, description="Name search"),
):
    return {"id": product_id, "page": page, "search": search}

Use Query() without a value for a required query parameter. Use alias when the public name differs from the Python argument:

@app.get("/products")
async def list_products(
    page_size: int = Query(25, alias="pageSize", ge=1, le=100),
):
    return {"page_size": page_size}

Invalid values return Flaxon's normal 422 validation response and the same constraints appear in the generated schema.

Request and response schemas

Native Flaxon schemas work without an extra dependency:

from flaxon.validation import IntField, Schema, StrField


class CreateProduct(Schema):
    name = StrField(required=True, min_length=2, max_length=120)
    stock = IntField(required=True, minimum=0)


@app.post(
    "/products",
    summary="Create a product",
    tags=["products"],
    responses={201: (CreateProduct, "Product created")},
)
async def create_product(product: CreateProduct) -> CreateProduct:
    return product

The request body and 200 response reference a reusable component schema. The responses mapping accepts a description string, a schema class, a (schema, description) tuple, or a raw OpenAPI response object.

Pydantic is optional. Install flaxon[pydantic] to use Pydantic request and response models; their model_json_schema() output is copied into the OpenAPI components section:

from pydantic import BaseModel


class Product(BaseModel):
    name: str
    price: float


@app.post("/products")
async def create(product: Product) -> Product:
    return product

Docstrings and metadata

The first non-empty docstring line becomes the operation summary and remaining lines become its description. Explicit route metadata wins over the docstring:

@app.get("/reports", tags=["reporting"], deprecated=True)
async def reports() -> list[dict]:
    """List reports.

    Reports are filtered by the current user's organization.
    """
    return []

Every named route receives an operationId. Use security when the endpoint requires a security scheme that your application defines:

@app.get("/account", security=[{"bearerAuth": []}])
async def account():
    return {"authenticated": True}

OpenAPI describes the contract; it does not authenticate requests. Keep your real authentication middleware or endpoint dependency in place.

Modules and routers

Routes mounted with include_router() or mount_module() are discovered from the final application registry. Metadata survives the mount, so a feature can own its documentation next to its routes:

from flaxon import Router

catalog = Router(prefix="/catalog")


@catalog.get("/products", tags=["catalog"], summary="List products")
async def products() -> list[dict]:
    return []


app.include_router(catalog, prefix="/api")

The generated path is /api/catalog/products. WebSocket routes are not added to OpenAPI because OpenAPI describes HTTP operations; document WebSocket messages separately with the WebSocket guide.

Protect documentation in production

Documentation is public when enabled unless you provide a guard. The guard can be synchronous or asynchronous and may return a Response for a custom denial page:

from flaxon import HTTPException


async def docs_guard(request):
    if request.headers.get("x-docs-key") != "internal-preview":
        raise HTTPException(403, "Documentation is restricted.")
    return True


app.enable_openapi(
    title="Internal API",
    docs_guard=docs_guard,
    protect_docs=True,
)

protect_docs=True requires a guard so a deployment cannot accidentally claim that its documentation is protected. The default Swagger UI does not persist authorization tokens in browser storage. Set persist_authorization=True only when that tradeoff is intentional.

For an offline or security-sensitive deployment, point swagger_asset_url and redoc_asset_url at assets served by your own application or reverse proxy.

Generate a checked-in specification

The CLI can generate a file for clients, SDK tooling, or CI:

flaxon docs app:app --output openapi.json

Use --include-internal only when you intentionally want framework routes such as /health and /metrics in the exported document. In CI, fail when a developer changed routes without updating the checked-in file:

flaxon docs app:app --output openapi.json --check

The check compares parsed JSON, so whitespace and indentation do not create false failures. It reports a non-zero exit code when the file is missing, invalid, or out of date.

Complete copy-paste application

from flaxon import Flaxon, Query
from flaxon.validation import Schema, StrField


class SearchResult(Schema):
    title = StrField(required=True)


app = Flaxon(
    "search-api",
    openapi={
        "title": "Search API",
        "version": "1.0.0",
        "description": "A small, documented Flaxon service.",
    },
)


@app.get("/search", tags=["search"])
async def search(q: str = Query("", min_length=1, max_length=80)) -> list[SearchResult]:
    return [{"title": q}]

Run it with:

flaxon run app:app --reload

Then open http://127.0.0.1:8000/docs or http://127.0.0.1:8000/redoc.

Use this capability in a full-stack app

Flaxon serves Python APIs and Teloce interfaces in one project. Keep validation, authorization and privileged operations on the server; components call those endpoints and present their results. Follow the full-stack lessons and Teloce integration reference to connect this capability to pages, components and application modules.