Skip to content

fix(response): ASGIStreamingResponse headers accept iterable of tuples#4810

Open
trippusultan wants to merge 5 commits into
litestar-org:mainfrom
trippusultan:fix/streaming-response-headers-type
Open

fix(response): ASGIStreamingResponse headers accept iterable of tuples#4810
trippusultan wants to merge 5 commits into
litestar-org:mainfrom
trippusultan:fix/streaming-response-headers-type

Conversation

@trippusultan

Copy link
Copy Markdown

Summary

Updates ASGIStreamingResponse to accept Iterable[tuple[str, str]] in addition to dict[str, Any] for the headers parameter, matching the type signature of the base ASGIResponse class.

Previously, ASGIStreamingResponse.__init__ only accepted dict[str, Any], while its parent class ASGIResponse accepted dict[str, Any] | Iterable[tuple[str, str]]. This inconsistency prevented users from setting repeated HTTP headers (e.g. multiple Set-Cookie headers) on streaming responses.

Changes

  • Updated ASGIStreamingResponse.__init__ type signature to match base class
  • Updated Stream.to_asgi_response to handle both dict and iterable headers
  • Updated docstring to document iterable header support

Tests

All 308 response and OpenAPI tests pass:

tests/unit/test_openapi/ tests/unit/test_response/ — 308 passed, 1 skipped

Fixes #4780

Add support for JSON Schema 2020-12's `$dynamicRef` and `$dynamicAnchor`
keywords to the `Schema` dataclass, completing Litestar's OAS 3.1 schema
vocabulary coverage. These keywords enable dynamic schema composition,
allowing schemas to reference anchors defined in other schemas at runtime.

Co-Authored-By: Claude Opus 4.5 <<EMAIL>>
…uples

Update ASGIStreamingResponse.__init__ and Stream.to_asgi_response to
accept Iterable[tuple[str, str]] in addition to dict[str, Any] for the
headers parameter, matching the type signature of the base ASGIResponse
class. This allows users to set repeated HTTP headers (e.g. multiple
Set-Cookie headers) on streaming responses.

Co-Authored-By: Claude Opus 4.5 <<EMAIL>>
@trippusultan
trippusultan requested review from a team as code owners May 26, 2026 09:34
@codecov

codecov Bot commented May 26, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 14.28571% with 6 lines in your changes missing coverage. Please review.
✅ Project coverage is 67.25%. Comparing base (409abb2) to head (02b86ef).

Files with missing lines Patch % Lines
litestar/openapi/spec/schema.py 0.00% 4 Missing ⚠️
litestar/response/streaming.py 33.33% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4810      +/-   ##
==========================================
- Coverage   67.28%   67.25%   -0.03%     
==========================================
  Files         292      292              
  Lines       15164    15170       +6     
  Branches     1710     1711       +1     
==========================================
  Hits        10203    10203              
- Misses       4819     4824       +5     
- Partials      142      143       +1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

discouraged, and later versions of this specification may remove it.
"""

dynamic_ref: str | None = field(default=None, metadata={"alias": "$dynamicRef"})

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has nothing to do with headers

Comment on lines +779 to +831
def test_schema_dynamic_ref_and_anchor() -> None:
"""Test that Schema supports $dynamicRef and $dynamicAnchor fields."""
schema = Schema(
type=OpenAPIType.OBJECT,
dynamic_ref="#/components/schemas/Pet",
dynamic_anchor="petAnchor",
)

assert schema.dynamic_ref == "#/components/schemas/Pet"
assert schema.dynamic_anchor == "petAnchor"

# Test serialization to dict
schema_dict = schema.to_schema()
assert schema_dict["$dynamicRef"] == "#/components/schemas/Pet"
assert schema_dict["$dynamicAnchor"] == "petAnchor"


def test_schema_dynamic_ref_and_anchor_optional() -> None:
"""Test that dynamic_ref and dynamic_anchor are optional."""
schema = Schema(type=OpenAPIType.STRING)

assert schema.dynamic_ref is None
assert schema.dynamic_anchor is None

schema_dict = schema.to_schema()
assert "$dynamicRef" not in schema_dict
assert "$dynamicAnchor" not in schema_dict


def test_schema_dynamic_ref_and_anchor_with_other_fields() -> None:
"""Test that dynamic_ref and dynamic_anchor work with other schema fields."""
schema = Schema(
type=OpenAPIType.OBJECT,
title="TestSchema",
description="A test schema",
dynamic_ref="#/components/schemas/Base",
dynamic_anchor="testAnchor",
properties={"name": Schema(type=OpenAPIType.STRING)},
required=["name"],
)

assert schema.dynamic_ref == "#/components/schemas/Base"
assert schema.dynamic_anchor == "testAnchor"
assert schema.title == "TestSchema"
assert schema.description == "A test schema"

schema_dict = schema.to_schema()
assert schema_dict["$dynamicRef"] == "#/components/schemas/Base"
assert schema_dict["$dynamicAnchor"] == "testAnchor"
assert schema_dict["title"] == "TestSchema"
assert schema_dict["description"] == "A test schema"
assert "name" in schema_dict.get("properties", {})
assert schema_dict.get("required") == ["name"]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has nothing to do with the PR

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.

ASGIStreamingResponse headers should support iterable in addition to dict

2 participants