Skip to content

docs(planning): record decision to keep ClassProperty media_type#20

Merged
lesnik512 merged 1 commit into
mainfrom
docs/decision-classproperty-ordering
Jul 4, 2026
Merged

docs(planning): record decision to keep ClassProperty media_type#20
lesnik512 merged 1 commit into
mainfrom
docs/decision-classproperty-ordering

Conversation

@lesnik512

Copy link
Copy Markdown
Member

What

Records the outcome of architecture-review candidate 3 (collapse the ClassProperty descriptor + per-route VersionedJSONResponse).

Decision: rejected. The descriptor stays.

Why

The deciding discovery: ClassProperty's lazy class-level read is what makes init_fastapi_versioning order-independent with respect to include_router. The two shipped usages prove it by disagreeing:

  • README.mdinclude_router(...) then init_fastapi_versioning(...) (init last).
  • tests/conftest.pyinit_fastapi_versioning(...) then include_router(...) (init first).

Both work only because the vendor is read lazily at access time. Every proposed collapse trades that away:

  • A1 (resolve in init by iterating app.routes) requires routes to be mounted first → imposes an "init last" contract and breaks the init-first order.
  • A2 (resolve in a startup/lifespan handler) keeps order-independence but couples init into app lifespan.
  • B (delete per-route classes; version content-type in middleware) can't distinguish a VersionedAPIRoute response from a plain one at ASGI send time, so it would over-stamp the vendor content-type onto non-versioned responses.

Mechanics verified against FastAPI 0.139.0 / Starlette 1.3.1 (openapi/utils.py:279 reads response_class.media_type live at schema-gen; APIRoute.__init__ captures the class object in the handler closure). Full rationale and revisit triggers in the decision file.

No code changes. just check-planningplanning: OK; appears under ## Decisions in just index.

Architecture-review candidate 3 proposed collapsing the ClassProperty
descriptor + per-route VersionedJSONResponse. Rejected: the descriptor's lazy
class-level read is what decouples init_fastapi_versioning timing from route
registration. The README calls init after include_router; the tests call it
before; both work only because of that laziness. Every collapse (eager init
resolution, startup hook, or middleware content-type) trades it for an
init-ordering contract, lifespan coupling, or over-stamping non-versioned
responses. Records the constraint and revisit triggers.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@lesnik512 lesnik512 merged commit 306a6f1 into main Jul 4, 2026
6 checks passed
@lesnik512 lesnik512 deleted the docs/decision-classproperty-ordering branch July 4, 2026 12:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant