I recently implemented a InitPluginProtocol
that, among other things, adds a bunch of response headers to the app. I ran into the problem that the type of AppConfig.response_headers
is ResponseHeaders
, which is a union of Sequence[ResponseHeader]
and Mapping[str, str]
: https://github.com/litestar-org/litestar/blob/main/litestar/types/composite_types.py#L53
Because of this, there was no straightforward way to add response headers in a type correct way. I ended up doing this:
response_header_list: list[litestar.datastructures.ResponseHeader]
if hasattr(app_config.response_headers, "items"):
# Mapping[str, str]
response_header_list = [
litestar.datastructures.ResponseHeader(name=name, value=value)
for name, value in app_config.response_headers.items()
]
else:
# Sequence[ResponseHeader]
response_header_list = list(app_config.response_headers)
response_header_list.extend(_headers.COMMON_RESPONSE_HEADERS)
app_config.response_headers = response_header_list
If AppConfig.response_headers
was not a union, or even just list[ResponseHeader)
, this would have been as simple as using list.extend
. I know that, ultimately, the response headers are type narrowed into tuple[ResponseHeader]
. I just wish that, e.g., it would have been either type narrowed to a list first in the AppConfig
, or that the app init was less generous with the allowed input formats. AppConfig.response_headers
being a union of two immutable types with different signature makes modification unnecessarily complex.
For example, if AppConfig.response_headers
was list[ResponseHeader]
, I could just do this (of course, this example is an artificial toy example and there is no great reason for this plugin to exist as-is):
from litestar.plugins import InitPluginProtocol
from litestar.datastructures import ResponseHeader
from litestar.config.app import AppConfig
class AddSomeResponseHeadersPlugin(InitPluginProtocol):
def __init__(self, response_headers: list[ResponseHeader) -> None:
self._headers = response_headers
def on_app_init(self, app_config: AppConfig) -> AppConfig:
app_config.response_headers.extend(self._headers) # typing ok!
return app_config
There are ways to implement this which break backwards-compatibility, and there are ways that don't. For example, if AppConfig.response_headers
was changed to list[ResponseHeader]
and the conversion to this type happened inside Litestar.__init__
, before InitPluginProtocol.on_app_init
was called with the AppConfig
, thus preserving the arguments to Litestar.__init__
, then all compatibility would be preserved, since list[ResponseHeader]
is in fact of type ResponseHeaders
(just much more narrow).
No response
Pay now to fund the work behind this issue.
Get updates on progress being made.
Maintainer is rewarded once the issue is completed.
You're funding impactful open source efforts
You want to contribute to this effort
You want to get funding like this too