Skip to content

Improvement plan #3

Open
Open

Description

@Siyet

A review of the router against FastAPI 0.142.2 and 0.143.3, with each behavior finding
compared against a plain FastAPI route with Pydantic models, found the issues below. They are
grouped into steps; each step will be a separate pull request.

1. Request handling and CI (done in #4, released in 0.0.2)

  • A JSON body without a Content-Type header is accepted even with FastAPI's default
    strict_content_type=True. FastAPI rejects it, because such a request can be sent
    cross-origin without a CORS preflight.
  • Deeply nested JSON in a body returns 500 (RecursionError) instead of 400.
  • A NaN or infinite float in a typed response can return 500; Pydantic encodes it as
    null.
  • A body that does not match its schema returns 422 before dependencies run, so an
    unauthenticated request with such a body gets 422 instead of the 401 from an
    authentication dependency.
  • -> None is treated as a typed null response, so status_code=204 is rejected at
    registration and the OpenAPI schema is {"type": "null"}.
  • Form() parameters and File() parameters of type bytes are rejected at
    registration.
  • There is no CI for pushes and pull requests; tests run only when a release is
    tagged.

2. OpenAPI document

  • An Enum used both in a parameter and inside a Struct makes /openapi.json return
    500 (Conflicting OpenAPI component).
  • Enum parameter schemas reference #/$defs/..., which does not exist in the
    document.
  • Two Structs with the same name from different modules conflict.
  • install_openapi depends on the routers passed to it: a router that is not passed,
    a route added to a router after it was included, or a plain APIRouter leaves dangling
    references or fails. Webhooks and callbacks are not covered, and components of routes
    with include_in_schema=False are still added. Routes could be discovered from the
    application when the document is built, with the router arguments kept for
    compatibility.
  • Body(description=..., examples=...), a requestBody in openapi_extra and
    response examples are overwritten.
  • A Struct or list parameter with the same name as a path parameter becomes a request
    body instead of failing at registration, and the document is invalid.
  • The 415 response is not documented.

3. Request and response handling

  • pattern= on parameters is checked with Python re (unanchored search), so a
    trailing newline passes ^...$ and a backtracking pattern can block the event loop;
    Pydantic uses a linear-time engine. Body(pattern=...) and Field(pattern=...) inside
    containers are affected too.
  • Generator endpoints (JSON Lines and server-sent events) return 500 or fail at
    registration.
  • Untyped returns of values msgspec cannot encode (Path, IP addresses, HttpUrl,
    SecretStr, other objects) return 500; FastAPI falls back to jsonable_encoder.
  • The error for an integer parameter over the digit limit mentions
    sys.set_int_max_str_digits().
  • Body validation errors have loc ["body"] and only the first error; the path appears
    only inside the message text.
  • A typed return with a custom response_class is rejected at registration.

4. Packaging and typing

  • No py.typed, so type checkers treat the package as untyped.
  • MsgspecRoute is not exported, although route_class must extend it.
  • The sdist includes untracked local files; set an explicit include list.
  • Lint configuration, Dependabot for GitHub Actions, classifiers and a declared
    pydantic dependency.
  • Tests for sync endpoints, Body(embed=True), empty bodies and list query
    parameters.

5. Performance (not planned)

  • On routes with several query parameters, most of the parameter handling time is
    spent in FastAPI's generic extraction (request_params_to_args). A per-route extractor
    built at registration removed about 30 to 40 µs per request on a route with seven query
    parameters in a local in-process measurement. On the service from the README
    benchmarks that is an estimated 3 to 5% of the API CPU time per response, and the
    extractor would depend on more private FastAPI code, so this item is not planned.

Activity

  1. added a commit that references this issue on Oct 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions