Repository navigation
Releases: mathisarends/fastapi_canon
Release list
fastapi-canon 0.15.0
0.15.0 - 2026-11-04
Added
- Optional
fastapi-canon[mcp]integration: explicit featureMcpMountcontributions,
applicationMcpOptionswith/mcpand app-title defaults, and FastMCP-backed
McpServerregistration with compact DishkaInject[T]annotations. Composition
owns the MCP lifespan and isolated per-execution dependency cleanup. - Installed-wheel and public-index smoke checks cover the optional MCP extra,
including an HTTP tool call, injected input schemas and request-scope cleanup.
Breaking changes
- Replace
@channel.subscription()with@channel.stream(). The old decorator
is removed without an alias.AsyncIterator[T]declares JSON message streams;
AsyncIterator[bytes]declares binary frames. Binary input/output ports retain
upload and duplex support. Usecontent_typeandinput_content_typeonly for
binary transfers; message streams keepraises=and channel error declarations.
UnconstrainedAnyand mixed raw-byte/message payloads fail at registration. - Replace message-stream wire controls
<operation>.subscribeand
<operation>.unsubscribewith<operation>.openand<operation>.cancel.
Control acknowledgements, data and terminal messages now usestreamId.
OpenRPC describes the operation inx-rpc-streams, including framing,
direction, overflow and reconnect policy. Old control names and the old
x-rpc-subscriptionscontract are not accepted. Upgrade server and clients
together and regenerate both language targets. - Rename
RpcLimits.max_subscriptionstomax_streams; the default remains 100
logical message streams per connection. The limit error code is now
stream_limit. Binary sockets keep their existing
independent lifecycle and limits. - Generated Python message operations return an iterable stream resource. Prefer
async with client.jobs.progress(job_id=...) as stream:followed byasync for;
entering opens the operation before waiting for its first value and leaving
cancels it with cleanup. Direct iteration and explicitaclose()also work.
Generated TypeScript message operations now returnPromise<RpcStream<T>>:
useawait using stream = await client.jobs.progress({ jobId: ... })and
for await.close()and loop exit stop that stream. Binary receive operations
keep the same resource pattern. The common domain SDK also exposes managed
resources for JSON-RPC message streams. - Message-stream queue overflow is an explicit transport/consumer error rather
than silent truncation. Passive notification overflow policies and counters
remain available. Reconnect is still opt-in:reconnect=True/reconnect: true
reopens active message streams with fresh IDs, on the replacement transport;
old IDs are cancelled only on their issuing transport. Reopening restarts the
source and does not guarantee replay or exact continuation. Retry deadlines,
credential refresh, connection recovery, scoped errors, drain and binary
backpressure remain supported.
fastapi-canon 0.14.0
0.14.0 - 2026-11-03
Breaking changes
- Extend the public
Databasedeclaration withcheck_migrations_on_startup
(defaultTrue) andengine_context. Deployments that own migration execution
and validation can setcheck_migrations_on_startup=Falseon the same declaration
used by the CLI. Explicitdb checkremains available and strict. Replace an
engine instrumentation Dishka decorator, if desired, with
engine_context=SqlAlchemyInstrumentation(telemetry=telemetry, pool_name="backend"), imported from
fastapi_canon.integrations.opentelemetry.sqlalchemy. The immutable declaration
creates a fresh context for each engine and exits before pool disposal,
including failed startup. Custom context factories remain supported. - Extend
AlembicMigrationsandfastapi-canon dbwith explicit
downgrade(engine, revision)anddb downgrade <revision>. Supply the target
explicitly. Older targets are not compared with current model metadata;
require_current(),db checkand default startup validation still require
application heads. Keep application-owned Alembic downgrade revisions and use
application code compatible with the target schema. - Make database installation and adoption requirements explicit in migration
documentation: basefastapi-canonselects Dishka, FastAPI and Pydantic;
[database]adds async SQLAlchemy and AnyIO;[sqlite]adds aiosqlite;
[postgres]adds asyncpg;sqlmodelandmigrationsadd SQLModel and Alembic
respectively, on top of database dependencies. Select the extras your
application uses, for examplefastapi-canon[postgres,sqlmodel,migrations].
These dependencies were already optional in 0.13.0; this documents the required
installation choices rather than introducing a dependency removal. Integration
code remains in the same wheel. Applications can retain their own providers
and lifespans; the database integration is opt-in, andServiceScoperemains
independent of SQLAlchemy and Alembic.
Added
- Bundle the progressive
build-canon-backendskill with HTTP, resource,
telemetry, transport and testing guides. Install it into a consumer project
withfastapi-canon skill install; use--destinationfor a custom location.
fastapi-canon 0.13.0
0.13.0 - 2026-11-02
Breaking changes
-
Rename
RpcRoutertoCanonWebSocketRouterin imports and constructors, and
Telemetry.rpc_middleware()toTelemetry.websocket_middleware(). The old
names are removed without aliases. JSON-RPC channel, wire and generated-client
contracts, including the establishedrpckit.*metric names, are unchanged. -
WebSocket controller calls without per-message trace metadata now start
independent traces and link to the connection context instead of inheriting
its trace. Explicit message context still parents the call, and handler work
remains nested under it. Update trace queries that assumed all calls on one
connection shared a trace ID. No client instrumentation is required. -
WebSocket server composition now uses
CanonWebSocketRouterexclusively. Replace
RpcServicepluscreate_router(service)ordishka_router(service)with
CanonWebSocketRouterand include it directly inFeature(routers=[rpc])or FastAPI.
ReplaceRpcRoutes(router, ...).mount(endpoint)with options onCanonWebSocketRouter
and itssocket()orstream()declaration. Useresolver=Dishka()for
Dishka,context=async_dependencyfor a connection context, andserve=
for custom FastAPI handlers. The removed names have no compatibility aliases.
See the WebSocket migration guide. -
Compositionnow accepts features only through the keyword-only
features: Sequence[Feature] = ()option. ReplaceComposition(tasks, notifier)
withComposition(features=(tasks, notifier)), or pass a list with
Composition(features=[tasks, notifier]). ReplaceComposition(*features, ...)
withComposition(features=features, ...). Omission still means no features;
declaration order, duplicate checks and the immutable tuple snapshot are
preserved. Positional feature arguments now raiseTypeError. -
Unhandled HTTP exceptions are diagnosed by the ASGI server after Starlette
sends Canon's safe 500 response. Applications relying on the additional
fastapi_canon.error.handlerstraceback should retainuvicorn.errorand route
it through one application log handler. UseTelemetry(logs=False)when that
server diagnostic should be the only exception log. Internally consumed
response-validation and rendering failures still retain their Canon diagnostic. -
Composition-owned HTTP dependency scopes now end after response validation and
before the response is sent. Remove application dependencies that duplicate
this scope management. Streams and background tasks must open their own short
ServiceScopeinstead of retaining request-owned resources. The minimum
FastAPI version is now 0.121 for function-scoped dependency cleanup. WebSocket
session/request scope behavior is unchanged.
Added
-
CanonWebSocketRouter(path, channels=[...])mounts one JSON-RPC WebSocket endpoint
as a FastAPI router. Use it inFeature(routers=[...])and call its
contract()method to export OpenRPC for the same channels. -
Composition(features=features, request_logging=True)emits structured completion/abort
records onfastapi_canon.access, including route templates, sent status,
streaming response duration, Canon problem codes and available server-span IDs.
It defaults to disabled and works without the Canon OTel extra. -
The reference telemetry demo exports ordinary Python service logs and request
records through one OTLP path to Loki, with provisioned Loki/Tempo links in both
directions for the distributed tasks-to-notifier request. -
Optional
Databaseintegration with SQLite/aiosqlite and PostgreSQL/asyncpg,
app-owned engines, request-owned sessions, commit on successful scope exit,
rollback on exceptions/cancellation, and SQLModel session support. SQLite
connections enforce foreign keys and explicit transaction control. -
ServiceScope[Service]for workers and long-lived operations that need a
fresh, short dependency scope using the same application providers. -
Application-owned Alembic revisions through
AlembicMigrationsand
fastapi-canon db init|revision|upgrade|check. The application checks revision
heads at startup; applying migrations remains an explicit deployment step. -
Typed custom-session factory aliases and injectable PostgreSQL transaction
advisory locks. SQLite rejects unsupported advisory locking unless omission is
explicitly configured. Owned table/column presence is checked even behind a
current revision; existing schemas are repaired with forward migrations.
Development
- Extend post-upload public-index verification to the database, SQLite,
PostgreSQL, migrations and SQLModel extras, including SQLite transactions and
Alembic upgrades, across twelve installation combinations.
Documentation
- Add a consolidated 0.12-to-0.13 upgrade guide covering composition, WebSocket
routing, HTTP scope ownership and telemetry migration. - Align current dependency requirements, integration installation guides and
the seventeen-combination installed-wheel matrix with the prepared release.
Keep published-version records separate from unreleased source APIs.
fastapi-canon 0.12.0
0.12.0 - 2026-11-02
Breaking changes
- Composition's Dishka containers now reserve
Telemetryfor the application
configuration, in every contributed component. Remove customTelemetry
bindings; inject the composition's instance instead. Without composition
telemetry, infrastructure receivesTelemetry.disabled(). In standalone
containers, explicitly addoptions.provider()(or
Telemetry.disabled().provider()). SDK providers remain borrowed. instrument(Port, OtherPort, ...)now requires at least one positional port
and always returns a tuple of immutable declarations, including for a single
port. Sharedexpectedandcomponentoptions apply to every port in the call.
ReplaceFeature(instrumentation=[instrument(Port)])with
Feature(instrumentation=instrument(Port)). Combine ports with the same options
in one call; useinstrumentation=[*instrument(FirstPort), *instrument(SecondPort, expected=(ExpectedError,))]for distinct groups.
Replaceinstrument(port=Port)withinstrument(Port).- HTTP requests excluded by
Telemetry.excludenow also suppress participating
downstream OpenTelemetry instrumentation, such as HTTPX, for the request's
execution context. Remove application middleware that duplicates this
suppression or re-evaluates the same exclusion predicate. Native HTTP telemetry
and Canon ports also respect inherited OpenTelemetry suppression; HTTP-only
suppression leaves port instrumentation enabled. WebSocket/RPC exclusion
configuration is unchanged. Theotelextra now includes the OpenTelemetry
instrumentation package for its public suppression helpers. - Remove
fastapi_canon.testing.telemetry.SpanCapturefrom the distribution.
Applications should maintain their own trace-capture fixture using the
OpenTelemetry SDK’s in-memory exporter; the repository fixture provides an example.
Added
- Explicit, lifetime-scoped
instrument_httpx(client, telemetry)and
instrument_sqlalchemy(engine, telemetry)adapters in their documented
integration modules. Both respect application-local signal settings and
request suppression and remove only their own instrumentation. HTTPX/HTTPX2
reuse the public contrib per-client API; SQLAlchemy uses engine-local event
listeners without wrapping factories or changing global instrumentors. - Opt-in
otel-httpxandotel-sqlalchemyextras, including SQLAlchemy's asyncio
dependencies for sync/async engine support. Resource and SDK lifecycle
remains application-owned. URLs, SQL text and exception messages are omitted
by default;capture_url=Trueandcapture_statement=Trueexplicitly opt into
potentially sensitive text. Headers, bodies and SQL parameters are not captured. - Engine pool observations independent of query/request suppression, plus
installed-wheel FastAPI bridge checks against 0.143.0 and the locked version.
Native configuration drift now fails before application installation.
Development
-
Build Canon directly from the repository root. Source lives in
fastapi_canon/;
tests, examples and integration guides no longer live in separate package
projects. Run development commands from the root afteruv sync --frozen --all-groupsandpnpm install --frozen-lockfile --ignore-scripts. Public imports,
extras and wire contracts are unchanged. -
Public-index release verification also installs the new
otel-httpxand
otel-sqlalchemyextras and exercises their resource adapters.
fastapi-canon 0.11.0
0.11.0 - 2026-11-01
This release replaces provider-level telemetry declarations with feature-owned
instrumentation and includes the generated Python RPC client fix below.
Breaking changes
- Remove
fastapi_canon.integrations.opentelemetry.observewithout an alias.
Replace Provider class declarations withFeature(instrumentation=[ instrument(Port, expected=(ExpectedError,)), ...]), importinginstrument
from the same integration. Remove telemetry-only providers/features; spans now
use the feature declaring their instrumentation ascanon.feature. For named
Dishka bindings, passcomponent="name"toinstrument. Composition creates
decorators only when telemetry is enabled; the original providers remain
usable directly in Dishka containers.
Added
- Instrument asynchronous
__call__use cases, including inherited methods,
with the same span, metric, exclusion, exception-privacy and cancellation
contracts as public async port methods. Span names useUseCase.__call__. - Immutable instrumentation declarations and application-local generated
decorators allow one feature/provider instance to be reused by enabled and
disabled applications without sharing instrumentation state.
Changed
- Expand the README and guides with core HTTP contracts, generated domain SDKs,
shared problem handling and source error-contract checking examples. - Workspace TypeScript tooling uses the root-pinned pnpm version and one shared
pnpm-lock.yaml. For source development, use Node.js 24 and run
pnpm install --frozen-lockfile --ignore-scriptsat the workspace root; replace
package-local npm commands with the pnpm commands in the contributing guide.
Published Python runtime dependencies are unchanged.
Fixed
- Generated Python RPC clients keep their undocumented error dispatch tables
private and import problem classes through the existing runtime package facade.
Regenerate clients to remove Smelt SMT319/SMT320 findings. Declare application
errors in the service contract; dispatch tables are not consumer extension
points. Error class exports and wire behavior are unchanged. - The publication job installs the shared TypeScript tooling before verifying
public-index installs, so generated-client compilation can run after upload.
fastapi-canon 0.10.0
0.10.0 - 2026-11-01
Breaking changes
-
Regenerated TypeScript HTTP clients return
undefinedfor bodyless success
responses,nullfor JSON null, and a JSON-or-void union for mixed success
statuses. Regenerate SDKs and remove checks fornullthat meant "no HTTP
response body"; await bodyless calls normally or check forundefined.
Empty JSON and unexpected bodies for bodyless contracts now raise
ProtocolError; handle that error instead of accepting a silent null value. -
Regenerated Python HTTP clients validate the response schema for the actual
status, with exact codes taking precedence over2XX. Empty JSON, bodies on
bodyless responses, and payloads matching only another status now raise
ProtocolError. Regenerate SDKs and correct those server responses instead of
relying on their previous acceptance. Required query/header parameters cannot
be null; provide a non-null value. Optional null parameters continue to be
omitted. -
Rename the console command from
canontofastapi-canon, including all
transport and check subcommands. Update scripts and CI invocations; the Python
module entry point remainspython -m fastapi_canon. Common generation uses
fastapi-canon.tomlwith[codegen], or[tool.fastapi-canon.codegen]in
pyproject.toml. Move version, sources and targets into that codegen section. -
Use the resolved RFC 9457
typeURI as the discriminator for Canon's compiled
same-status HTTP problem unions. Regenerate clients and update schema consumers
that expectedpropertyName: code;coderemains a stable Canon extension.
A union with ambiguous type identities, including a domainabout:blank
variant combined with a generic problem of the same status, now fails schema
compilation. Give business-specific problems distinct, stable type URIs. -
Problem.statusis optional for embeddings and only accepts an integer when
present. Callers reading it directly must handleNone; do not pass booleans,
numeric strings, or floats. HTTP responses still emit their actual status. -
Problem.as_dict()preserves explicitly null extension values while omitting
absentstatus,detail, andinstance. HTTP schemas describe optional
detailandinstanceas strings; omit absent values instead of emitting null. -
Use one Canon 0.10.0 version across the workspace and generated artifact
metadata. -
Canon streams now send terminal
canon.problemorcanon.completeevents.
Declare processing errors withstream_raises=and update manual consumers to
stop on either terminal event. RawStreamRouterbehavior is unchanged. -
Regenerated SSE clients raise
ProblemErrorfor HTTP problem responses and
terminal stream problems. Catch that class instead ofHttpErrorfor problem
bodies. Unexpected EOF without completion is a transport error for Canon
streams. Regenerate Python and TypeScript clients after upgrading. -
ProtocolDefinitionErrornow shares Canon'sErrorConfigurationErrorbase.
Added
-
Shared
Errordefinitions in RPC channel and operationraises=, with
error_registry=onRpcChannel. Canonical domain failures use JSON-RPC
error.data.problem, retaining the numeric JSON-RPC error code and message. -
RPC routes contribute channel catalogs to composition. Export RPC contracts
withservice.contract(..., app=app)to use composition's resolved type URIs. -
SSE profile version 1, declared terminal problem schemas, safe processing
failure handling, generator cleanup, and explicit successful completion. -
Python and TypeScript SDK problem/error runtimes from a common source;
ProblemError.problem,TransportError, andProtocolError, plus known RPC
error subclasses selected by type URI. Unknown problems preserve extensions. -
Generated Python RPC calls/subscriptions validate parameter objects by wire
aliases, including all-required parameters, so shared DTOs use one mapping. -
Typed RPC method decorators and default-context endpoints preserve normal
application type inference. The executable API example is checked with mypy. -
An executable example defining one error and registering it with HTTP, SSE,
and RPC, and a root decision record for future implementation work. -
Version-1
fastapi-canon generateconfiguration and a common operations/model
plan for OpenAPI, OpenRPC and WebRTC sources, with live export, saved/offline inputs,
read-only drift checks, explicit identity/name conflict resolution and one
ownership manifest per SDK output. -
A generated domain facade (
client.projects.get/cancel/events) with a JSON
HTTP binding, internal SSE/JSON-RPC/socket bindings, TypeScript WebRTC sessions,
shared canonical model declarations and one common error runtime per output.
Connections are lazy; injected clients remain caller-owned. -
Explicit
include-operationsandexclude-operationson common codegen
sources, applied before model planning and binding generation. Adopt part of
an existing OpenAPI/OpenRPC/WebRTC contract without modifying the export;
original input hashes and selection settings remain in the SDK manifest.
Fixed
-
Generated TypeScript HTTP clients omit optional null query/header parameters,
give exact response statuses precedence over2XX, and wrap connection
failures while reading response bodies inTransportError, including problem
responses. Explicit cancellation retains its native abort error. -
Release notes include consecutive older unreleased changelog sections, so
upgrading from published 0.8.1 to 0.10.0 includes the unpublished 0.9.0 package
and telemetry migrations below. -
Enforce architecture and test-quality policies with pinned Smelt in the
workspace gate, pre-commit and CI. Mirror focused HTTP tests, bound async waits
and compiler subprocesses, and make generated-output and async outcomes explicit. -
Generate Python validation for valid string patterns using lookarounds or
backreferences, including decimal-string schemas from earlier Pydantic
exporters. Compiled Python patterns preserve validation in fields and aliases. -
Preserve literal discriminator fields through nested union aliases, including
variants with several tag values, so generated Python SDKs import and validate.
To adopt the common workflow, configure codegen.sources/codegen.targets in
fastapi-canon.toml and choose a fresh SDK output. Specialized generator commands and their manifests
remain available. See docs/problems.md and the root codegen guide.
Included unpublished changes
The following changes are included in 0.10.0 and were not published separately.
0.9.0 - unreleased
Breaking changes
- Consolidate SSE, WebSocket RPC/sockets and WebRTC into the
fastapi-canon
distribution. Replace dependencies onfastapi-streams,fastapi-rpckitand
fastapi-webrtcwith Canon'ssse,websocketsandwebrtcextras. Replace
fastapi-canon[streams]withfastapi-canon[sse]. All transport source and
generator resources ship in the same wheel; extras select dependencies. - Migrate imports to
fastapi_canon.integrations.sse,
fastapi_canon.integrations.websocketsandfastapi_canon.integrations.webrtc.
Their public exports includeCanonStreamRouterandCanonWebRtcRouter.
Update shortfastapi_canon.sse,.websocketsor.webrtcpaths from earlier
prepared snapshots. Replace the publishedfastapi_canon.integrations.streams
path withfastapi_canon.integrations.sse. WebSocket framework adapters now
live underfastapi_canon.integrations.websockets.adapters; update former
fastapi_rpckit.integrationsimports to that prefix. The former top-level
modules and console scripts are removed. Usefastapi-canon sse,
fastapi-canon websocketsandfastapi-canon webrtcfor generator commands. - Regenerate clients: generator metadata now uses the unified Canon version. Existing
generated layouts, contract formats and transport behavior are retained,
including JSON-RPC 2.0 andfastapi-webrtc.v1. Socket binding entry points move
tofastapi_canon.integrations.websockets.socket_bindings; update binding
package metadata.
See the package migration guide for commands. - Extend the public
Compositionconstructor withtelemetry=. Update wrappers
or signature snapshots that mirror this constructor. Existing compositions
without telemetry keep their behavior. To opt in, installfastapi-canon[otel]
and passTelemetry(...); registerobserve(Port)as a Dishka Provider class
attribute beside the binding it decorates.Featurerequires no new metadata.
Added
- Return unified development and future releases to
mathisarends/fastapi_canon
with the complete imported Git history. Update package links and publisher
configuration; preserve historical release evidence in its original repository. - One
fastapi-canoncommand andpython -m fastapi_canonentry point, including
fastapi-canon check errors. Root CLI help loads no transport generators. - Optional
codegen,aiortcandoteldependencies in Canon.
Native engine and generation dependencies remain absent from the base install. - Fresh-wheel checks for the base package, each feature, codegen-only and
combined installations, including minimum dependency profiles. - Optional, exporter-free OpenTelemetry integration using FastAPI >=0.143 native
telemetry and application-owned providers. Core retains FastAPI >=0.115. - Dishka decorators for public async port methods, expected-exception events,
optional port-duration histograms, and scope/caching/finalizer preservation.
Port wrappers capture no argument values or exception messages/stack traces. - Native HTTP server-span Problem Details enrichment with
canon.problem.code;
only 5xx seterror.typeand ...
v0.4.0
v0.3.0
v0.2.0
What's Changed
- Plan/v0.2.0 by @mathisarends in #1
New Contributors
- @mathisarends made their first contribution in #1
Full Changelog: https://github.com/mathisarends/fastapi_canon/commits/v0.2.0