Allow streamable response classes

Basically classes such as `StreamingResponse` in `starlette` cannot work unless specified directly in the response-type due to this serialization concept (which they always fallback to use JSON)

There is the alternative which I opted out of for now, which is pass a `response_serialize: bool` parameter throughout the entire flow, it might be better but I wanted to avoid API changes (even through defaults) until any maintainer gives his opinion on the change

example usage:
```
# Here `response_class` is only used for documentation
@app.get('/test_before', response_class=StreamingResponse)
async def before_fix(msg: str):
    async def txt_generator():
        for i in range(10):
            yield f'event: something\ndata: {i}\n\n'
    return StreamingResponse(txt_generator())

# Here `response_class` is actually working
@app.get('/test_after', response_class=StreamingResponse)
async def after_fix(msg: str):
    async def txt_generator():
        for i in range(10):
            yield f'event: something\ndata: {i}\n\n'
    returntxt_generator()
```
This commit is contained in:
Omer Shamash 2024-04-15 13:20:54 +03:00 committed by GitHub
parent 3425c834cc
commit 653533566e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 13 additions and 11 deletions

View File

@ -293,17 +293,19 @@ def get_request_handler(
response_args["status_code"] = current_status_code
if sub_response.status_code:
response_args["status_code"] = sub_response.status_code
content = await serialize_response(
field=response_field,
response_content=raw_response,
include=response_model_include,
exclude=response_model_exclude,
by_alias=response_model_by_alias,
exclude_unset=response_model_exclude_unset,
exclude_defaults=response_model_exclude_defaults,
exclude_none=response_model_exclude_none,
is_coroutine=is_coroutine,
)
# Some response classes handle serialization themselves via iteration
if not hasattr(actual_response_class, 'body_iterator'):
content = await serialize_response(
field=response_field,
response_content=raw_response,
include=response_model_include,
exclude=response_model_exclude,
by_alias=response_model_by_alias,
exclude_unset=response_model_exclude_unset,
exclude_defaults=response_model_exclude_defaults,
exclude_none=response_model_exclude_none,
is_coroutine=is_coroutine,
)
response = actual_response_class(content, **response_args)
if not is_body_allowed_for_status_code(response.status_code):
response.body = b""