✨ Make ServerSentEvent generic with typed data field by benmosher · Pull Request #15191 · fastapi/fastapi

and others added 2 commits

March 21, 2026 09:38
Introduce `ServerSentEvent[Data]` so endpoints that yield typed SSE
events get a `contentSchema` in the OpenAPI spec reflecting the data
payload type, while retaining full control over SSE fields (`event`,
`id`, `retry`, `comment`).

- `ServerSentEvent` now inherits from `Generic[Data]` with `data: Data`
- `validate_default=True` ensures `ServerSentEvent[Item]()` raises a
  ValidationError (data is effectively required when Data is concrete)
- `ServerSentEvent[Item | None]` allows optional data; bare
  `ServerSentEvent` is fully backward compatible (`Data=Any`)
- Added `get_sse_data_type()` helper (uses Pydantic's
  `__pydantic_generic_metadata__`) to extract `Data` from a
  parameterized `ServerSentEvent[Data]` annotation
- Routing layer now extracts `Data` from `ServerSentEvent[Data]` and
  uses it as `stream_item_type`, feeding it into the existing OpenAPI
  `contentSchema` pipeline
- Added tutorial006 and corresponding snapshot test
- Extended test_sse.py with generic SSE unit and app-level tests

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The previous commit added ServerSentEvent[Data] generic support and
tutorial006 but did not add a corresponding section to the SSE docs.
This adds the missing "Typed ServerSentEvent" section explaining the
generic syntax, validation behavior, and OpenAPI contentSchema benefit.

https://claude.ai/code/session_01GRv2sCmACvBQFX7fh7anWm
Bare `ServerSentEvent` (without a type parameter) now silently resolves
to `ServerSentEvent[Any]`, so existing code and the `_check_data_exclusive`
return annotation require no changes and pass mypy without `[type-arg]`
errors.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

@pre-commit-ci-lite

…e test

Pydantic BaseModel subclasses always have __pydantic_generic_metadata__, so
the `if not meta` early-return was dead code. Collapse it into a ternary and
add a test for a plain (non-parameterized) ServerSentEvent subclass to reach
the `not args` branch, bringing fastapi/sse.py to 100% coverage.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The test only fetched /openapi.json, leaving the generator body unreachable.
Add a /stream request inside the same TestClient context so the yield
executes, bringing tests/test_sse.py to 100% coverage.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>