github mr-fatalyst/fastopenapi v1.0.0rc2

pre-release6 hours ago

Added

  • Annotated parameter style following modern FastAPI conventions: Annotated[int, Query(ge=1)], Annotated[Item, Body()], Annotated[str, Header()], Annotated[X, Depends(f)] — supported in runtime resolution and OpenAPI generation
  • Automatic HEAD responses for GET routes on all frameworks (previously 405 on aiohttp, Sanic, Falcon, Tornado). An explicit @router.head(...) route always takes precedence; auto-HEAD does not appear in the OpenAPI schema
  • debug router flag: unhandled 5xx responses include exception details in the body only when debug=True
  • py.typed marker (PEP 561): the package's type annotations are now visible to users' type checkers
  • register_docs parameter for DjangoRouter as an explicit alternative to the app=True flag
  • Cross-framework integration test matrix: one shared application exercised against all 10 router variants (~100 scenarios each), including async endpoints and async/generator dependencies

Changed

  • Unhandled 5xx responses no longer leak exception text to clients — a generic message is returned, details go to the log (and to the body only with debug=True)
  • Malformed JSON returns 422 with an explicit "Invalid JSON in request body" error (was 400 in 0.7; silently treated as an empty body in rc1)
  • Plain str results are served as text/plain on every framework instead of being JSON-encoded (0.7) or framework-dependent (rc1); bytes results default to application/octet-stream
  • Response serialization unified into a single layer shared by all adapters: identical content-type defaults, custom headers preserved on 204/304 everywhere, case-insensitive Content-Type handling
  • Request payloads are parsed lazily: body/form/files are only read when the endpoint (or its dependencies) declare matching parameters
  • Security schemes are opt-in: schemas no longer include a default BearerAuth; SecuritySchemeType.OAUTH2 now requires explicit dict configuration (raises ValueError, no more example.com token URL)
  • Union annotations render as anyOf in OpenAPI (was a degenerate {"type": "string"}); with openapi_version="3.1.0" nullability uses type: [..., "null"] instead of the 3.0 nullable keyword
  • Name collisions get suffixes: distinct models sharing a __name__ produce User/User2 schemas instead of silently reusing the first one; duplicate autogenerated operationIds are deduplicated the same way
  • Async endpoints on sync-only routers (Flask, Falcon sync, Django sync) fail at registration time with a TypeError instead of a 500 on every request
  • Tornado 405 responses return the JSON error envelope with an Allow header (was tornado's HTML error page)
  • Framework extras loosened to major-version caps (aiohttp <4, starlette <1, sanic <26, quart <1, tornado <7); python-multipart is now installed with fastopenapi[starlette]
  • ReDoc pinned to 2.5.3 (was the floating redoc@next tag)
  • MissingRouter now names the missing framework and suggests the extra to install

Fixed

  • Generator (yield) dependencies stay open while the endpoint runs and finish with context-manager semantics — previously the cleanup code after yield executed before the endpoint was called, so a yielded resource (e.g. a DB session) was already closed when used. Now the code after yield runs after the response is built (in reverse creation order, sync and async), and when the pipeline fails the exception is thrown into the dependency — try/except/finally commit/rollback patterns work as in FastAPI. This includes request cancellation: CancelledError reaches the dependency instead of triggering the success path. A dependency that handles the exception suppresses it for dependencies finishing after it, and a failing teardown becomes the exception for the remaining ones, as with contextlib.ExitStack. An unsuppressed teardown failure on the success path (e.g. a failing commit) turns the response into a 500 instead of a silent 200 — unlike FastAPI, cleanup happens before the response is sent, so the adapter can still report it. Note: this also means framework-native streaming responses must not read from yielded resources lazily
  • Security scopes are part of the dependency cache key — two Security(dep, scopes=...) declarations with different scopes on one endpoint no longer share a cached result (the second check silently received the first one's scopes)
  • OpenAPI schema documents parameters declared inside Depends/Security dependenciesQuery/Header/Cookie/form/body parameters of (nested) dependency functions and class dependencies now appear in the operation, matching what the runtime actually requires; SecurityScopes injections and Header(alias="Authorization") stay hidden
  • Parameters inside dependencies follow HTTP method semantics — a bare Pydantic model in a dependency on GET/HEAD/DELETE resolves from query parameters, as it does on the endpoint itself (previously it always tried the request body)
  • Endpoints decorated with several HTTP methods keep each route's own metadata — previously the last decorator's meta (status_code, response_model, tags, ...) leaked into every method at runtime, and include_router() stamped it onto all included routes. Route metadata now travels with the route instead of being re-read from the endpoint function
  • Failed cleanup of yield dependencies is logged (fastopenapi logger) instead of being silently swallowed — a broken rollback/close no longer disappears without a trace
  • MissingRouter no longer masks broken import chains — the "X is not installed" hint is raised only when the framework package itself is absent; a broken transitive import (or an internal bug) surfaces its real error message
  • list[FileUpload] is documented as an array of binaries — the schema previously showed a single file while the runtime accepted several
  • Security nested inside Depends marks the operation as protected in the schema; with several registered security schemes each one is listed as an accepted alternative instead of silently picking the first. Scope lists are attached only to oauth2/openIdConnect schemes — other types get an empty array, as the spec requires
  • response_model=str / bytes are documented as text/plain / application/octet-stream, matching what the serializer actually sends (was always application/json). For str | None / bytes | None both media types are documented: None is serialized as a JSON null
  • Non-standard status codes (e.g. 299, 499) no longer crash schema generation — they get a generic Status <code> description; a duplicate explicit operationId is reported with a warning instead of silently producing an invalid schema
  • Route decorators preserve the endpoint's type for type checkers ((F) -> F instead of Any), so py.typed consumers keep full signatures of decorated functions
  • Broken imports in examples and README fixed (fastopenapi.routers.sync.flask, fastopenapi.routers.tornado)
  • aiohttp multipart uploads no longer fail with 500 — the JSON body reader drained the stream before the multipart parser could run
  • Falcon ASGI urlencoded forms and multipart no longer fail with 500 — async extractors got real async implementations instead of inheriting WSGI-only code
  • Falcon multipart with text fields no longer rejected as malformed (secure_filename probing on non-file parts)
  • Sanic Cookie(...) parameters no longer fail validation (cookie container yields value lists)
  • Falcon JSON and form bodies with Content-Type parameters (application/json; charset=utf-8) are no longer dropped
  • Multi-value form fields are preserved on Flask and Starlette (getlist/multi_items); same-name file uploads no longer collapse to the last file
  • Endpoints receive Pydantic model instances again — an rc1 regression passed list[dict] and degraded rich field types via model_dump() (0.7 behavior restored)
  • DELETE request bodies are read again — an rc1 regression ignored them (0.7 behavior restored, per RFC 9110 and FastAPI)
  • list[Model] and Model | None annotations work as body parameters without an explicit Body() marker
  • DjangoAsyncRouter with an explicit OPTIONS route no longer returns 500 (Django's view_is_async ignores the options handler)
  • 204/304 responses keep custom headers on every adapter (rc1 fixed only some); Tornado no longer crashes with an AssertionError on 304
  • Dependency resolution memory leak fixed: signature caches no longer grow per request; cross-request dependency execution locks removed (restores concurrency in threaded WSGI)
  • Response objects and tuples returned from endpoints with response_model no longer fail validation — explicit responses skip it, as in FastAPI
  • Nested model $defs are registered in components/schemas (no more broken $refs from models expanded into query parameters)
  • Mixed-type lists in responses no longer crash serialization

Removed

  • PaginationParams schema is no longer injected into every generated components/schemas
  • Auto-generated descriptions for page/limit/sort-style query parameters (the library no longer guesses the semantics of user parameter names)

Don't miss a new fastopenapi release

NewReleases is sending notifications on new releases.