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.jsonThe analyzer classifies changes as:
- Additive: compatible expansion, such as a new optional operation.
- Metadata: descriptions and other non-wire changes.
- Breaking: removal or tightening that rejects existing valid traffic.
- Unknown: JSON Schema behavior that cannot be proven safe.
Breaking and unknown changes return a failing exit status. Use
--diff-format json for automation.
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.