Skip to content

OpenAPI and compatibility

Tenchi derives OpenAPI 3.1 from composed contracts. The document describes the same types, headers, errors, media types, visibility, and successful response definitions enforced by the server and client.

Generate a document

openapi_schema() is a pure function:

from tenchi.openapi import openapi_schema


document = openapi_schema(
    api_routes,
    title="Todos",
    version="1.0.0",
    description="Todo service API",
    security={
        "bearerAuth": {"type": "http", "scheme": "bearer"},
    },
)

Pass only the application route group you want documented. Public contracts are exempted from global security through the same contract.public metadata used by authentication hooks.

Serve OpenAPI

from tenchi.openapi import openapi_route, swagger_ui_route
from tenchi.routes import route_group


routes = route_group(
    api_routes,
    openapi_route(
        api_routes,
        title="Todos",
        version="1.0.0",
    ),
    swagger_ui_route(title="Todos API"),
)

The default path is /openapi.json. The serving route is public by default and does not include itself in the document. Swagger UI defaults to /docs and loads that document through a relative URL, so ASGI root_path mounting keeps both routes aligned.

The default Swagger JavaScript and stylesheet are pinned CDN assets with subresource integrity metadata. Override swagger_js_url=, swagger_css_url=, and swagger_favicon_url= to self-host them. Set public=False on both routes when the API description requires authentication.

Store a canonical snapshot

uv run tenchi openapi --routes app.server.routes:api_routes \
  --title Todos --write openapi.json
uv run tenchi openapi --routes app.server.routes:api_routes \
  --title Todos --check openapi.json

--write produces deterministic, key-sorted JSON. --check is an exact equality check suitable for a repository test.

Classify changes

uv run tenchi openapi --routes app.server.routes:api_routes \
  --title Todos --diff openapi-baseline.json

The analyzer classifies changes as:

Breaking and unknown changes return a failing exit status. Use --diff-format json for automation.

Compare before updating

A compatibility gate needs a snapshot from the pull-request base, previous push, or previous release. If a breaking change and its new snapshot are committed together, comparing the generated document with that same snapshot proves only equality.

CI pattern

uv run tenchi openapi --routes app.server.routes:api_routes \
  --title Todos --diff-ref "$BASE_SHA" --snapshot openapi.json
uv run tenchi openapi --routes app.server.routes:api_routes \
  --title Todos --check openapi.json

--diff-ref resolves the snapshot inside the current Git repository and reads REF:PATH without changing the working tree. Missing refs and snapshots fail the command. Generated CI uses the pull request's base SHA; push checks retain exact snapshot validation without assuming a previous commit exists.

Use identical routes, title, version, description, and security options for generation, comparison, and snapshot checks.

Programmatic consumers can import analyze_openapi_compatibility() from tenchi.compatibility and inspect its structured CompatibilityReport.

Contracts marked webhook=True include x-tenchi-webhook: true on their OpenAPI operation. Adding that requirement is breaking because existing callers must begin signing deliveries; removing it is additive.