fastapi: FastAPI always returns content, even if 204 no content status code is set.
First check
- I added a very descriptive title to this issue.
- I used the GitHub search to find a similar issue and didn’t find it.
- I searched the FastAPI documentation, with the integrated search.
- I already searched in Google “How to X in FastAPI” and didn’t find any information.
- I already read and followed all the tutorial in the docs and didn’t find an answer.
- I already checked if it is not related to FastAPI but to Pydantic.
- I already checked if it is not related to FastAPI but to Swagger UI.
- I already checked if it is not related to FastAPI but to ReDoc.
- After submitting this, I commit to one of:
- Read open issues with questions until I find 2 issues where I can help someone and add a comment to help there.
- I already hit the “watch” button in this repository to receive notifications and I commit to help at least 2 people that ask questions in the future.
- Implement a Pull Request for a confirmed bug.
Example
from fastapi import FastAPI
from starlette.status import HTTP_204_NO_CONTENT
app = FastAPI()
@app.get("/", status_code=HTTP_204_NO_CONTENT)
def read_root():
print("d")
Description
Send a request with any HTTP Client, observe the traffic using tcpdump/wireshark - you’ll see that you get null as a response (content-length will be 4). This is extremely notable as this caused this issue https://github.com/encode/httpx/issues/1474 (The client doesn’t expect any data in that case) I would expect FastAPI to not return null when response is None.
Environment
- OS: macOS
- FastAPI Version [e.g. 0.3.0]: 0.63.0
- Python version: 0.63.0
About this issue
- Original URL
- State: closed
- Created 3 years ago
- Comments: 23 (8 by maintainers)
Commits related to this issue
- Explicitly return an empty response with 204 See https://github.com/tiangolo/fastapi/issues/2832 — committed to OlegZharkov/galaxy by davelopez 3 years ago
You could instead set the response class for that path operator to be
Responseinstead of the defaultJSONResponse. Then it won’t convertNoneinto JSON. So w/ your example above it would be:which correctly returns
b"".note, if you are doing this on multiple endpoints, you can set the default response class on your router, or even your entire app. https://fastapi.tiangolo.com/advanced/custom-response/#default-response-class
httptoolswill returnnullandh11will return empty but raises an exception if you don’t explicitly return a Response but declare the status code to be204.you have to explicitly return an empty Response instead of implicitly returning
None, which is what happens when you don’t return anything.also, see: https://github.com/tiangolo/fastapi/issues/2253
Thanks @falkben. I found this solution also but I believe it should be handled by the framework. It’s fairly simple to implement hence the PR I submitted. Returning 204 with data is invalid according to the standards so FastAPI should detect such scenario and handle it accordingly IMO
Is this fixed by https://github.com/tiangolo/fastapi/releases/tag/0.79.0 ?
I don’t think we need to handle all possible use-cases.
This bug is about the specific case where the route is defined with (default)
status_code=HTTP_204_NO_CONTENT, because if you do not also override other defaults (i.e. the extra setting @falkben describes, or expressly returning aReponsein your handler), FastAPI generates an invalid HTTP responses.Documenting
is less-kind to the library user than
as in the latter case, the user specifying their status code gets valid behaviour for that status code out-of-the-box, and retains exactly the same amount of control for the user to override the defaults that exists now. Overriding that
response_classdefault stops being mandatory, and natural things like not returning a value from a 204-typed API remain explicitly natural. And if the user decides that returning a body in their 204 response is actually desired, then that’s still possible explicitly.This also means the list of the HTTP status codes for which no response body is allowed by the standard is kept in the library code, rather than in the documentation and the user’s code-base.
I liked the idea of
EmptyResponseto be the defaultresponse_classwhen astatus_codewhich disallows response bodies is specified, but it seems Starlette upstream is going in a different direction there, simply explicitly excluding theContent-Lengthheader in 204 (and similar) responses, which has the effect that you cannot provide a message body in a 204 response. What you get if you try (i.e the example in this issue) is a 204 response with no body, plus a bunch of garbage data on the wire for which interpretations and handling varies. I’ve no idea what the various Python http libraries will make of this, but I suspect it won’t magically fix this problem by discarding any unintentionally-produced body data.unicorn --http httptools
Can you try to run with httptools instead of h11?