New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Automatically support HEAD method for all GET routes, as Starlette does #1773
Comments
encode/starlette#45 is only about static FileResponse. I don't know how a default should be set for a dynamic API. |
Not so, if you look at the related commit at https://github.com/encode/starlette/pull/132/files in Many web frameworks do this by default too, e.g. Flask (https://flask.palletsprojects.com/en/1.1.x/quickstart/#http-methods) and Django. It makes sense to do that because a server should respond to an https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/HEAD "The HTTP HEAD method requests the headers that are returned if the specified resource would be requested with an HTTP GET method. Such a request can be done before deciding to download a large resource to save bandwidth, for example." Clients use this for cache invalidation. The server just needs to run the route method, respond with the headers but discard the response body. Ideally, FastAPI would automatically add an OPTIONS method handler, too. This would help make FastAPI a first class web framework. This is safe even for a dynamic API, because to follow REST principles, HTTP GET routes should always be idempotent and have no side-effects (as should HEAD, PUT, DELETE, OPTIONS and TRACE). Only HTTP POSTs are allowed to have side effects (see https://tools.ietf.org/html/rfc7231#section-4.2.2). This behavior could be controlled by a flag defaulting to true. |
working on this |
Thanks @matthewlloyd for the very clear argument and especially for the self-contained example, that helps a lot. Indeed, here in the spec: https://tools.ietf.org/html/rfc7231#section-4.3.2 it says:
And the OpenAPI spec doesn't say anything contradicting it, so FastAPI should support it. I think ideally, it should handle HEAD requests automatically for GET requests, without adding them to the OpenAPI schema. I think HEAD operations should be added to OpenAPI only when explicitly declared in the code (ideally). Thanks @victorphoenix3 for working on this! Let me know if you need any help with it. |
As a side note, today, when making a HEAD request, you get a 405 returned, which according to spec*, should include an "Allow" header. I'm not if this is FastAPI or an underlying library returning this 405 - but maybe it should be changed as well. |
@victorphoenix3 Any progress on this issue? This bit me today. Is it just a matter of pulling from upstream? |
I'm on it. EDIT: Implemented first approach, but I didn't like it that much. I'm going to implement another solution, which is slower at startup time but doesn't have the problems I stated on that PR. |
I've implemented the second approach. It needs a refactor, and I need to think if there's incompatibility with I'll be waiting for @tiangolo's instructions before implementing/refactoring what is missing. |
This bit me today when implementing a Docker healthcheck using |
Got the same issue as our app is monitored by uptimerobot |
Bumping this thread, we are using this for health-checks, and pre-fetch verifications. Any updates would be great 👀 |
Btw if it's possible to help, I'm more than willing to. |
i found this issue today, and i play a bit, and this is what works for me (FastAPI 0.70.0): @router.head("/hello")
@router.get("/hello")
def read_root():
return {"Hello": "World"} so with $ http http://localhost:8080/hello HTTP/1.1 200 OK
content-length: 17
content-type: application/json
date: Mon, 06 Dec 2021 15:14:18 GMT
server: uvicorn
{
"Hello": "World"
} and then for HEAD method: $ http head http://localhost:8080/hello HTTP/1.1 200 OK
content-length: 17
content-type: application/json
date: Mon, 06 Dec 2021 15:14:15 GMT
server: uvicorn |
To avoid duplicating the request line,
|
This got me today and I was unaware of this open issue. I got help from stack overflow. |
Hey. I was taking a look at open issues I could contribute to and I stumble with this one. A way to implement this behavior without changing Fastapi or remembering to add the head decorators is to define an startup hook that add those head endpoints for you: @app.on_event("startup")
def add_default_head_endpoints(self) -> None:
for route in self.routes:
if isinstance(route, routing.APIRoute) and "GET" in route.methods:
new_route = copy(route)
new_route.methods = {"HEAD"}
new_route.include_in_schema = False
self.routes.append(new_route) As this is a desired behavior for Fastapi, I created a PR that implements this hook as a builtin. Feel free to take a look at it 😄 |
It's not desired to include routes on the "startup" event. I have two PRs about it already. I'll check later which one should be kept to review. |
I did take a look at your PRs and, as they were inactive, I decided to propose another approach. However, if you are going to retake the issue you'll probably know better than me the proper design decisions to take 😁. Thanks for taking a look!! |
Well... The PRs are not inactive... They were just not reviewed. 😅 But I improved my skills since I developed them, so I'll take another view. |
Hello, What about this? I need somewhat like this. |
and this is biting me as well :( HAproxy sends a HEAD request every few seconds to make sure the site is up i used @juantoca 's startup since there is no ways im going through a f ton of endpoints to add the head method to them a slight change since im not using a class for the app part
im on fastapi-0.104.1 and python 3.12 this would probably apply to OPTIONS method as well i guess altho that would need to be on every url right? im conveniently ignoring this but im sure it "should" be something included as a side note for anyone landing up here that ahs a proxy on the front end... this is how i solved it
you only need to have the options on the / route for the proxy to pickup the api is "alive"
|
First check
Example
Here's a self-contained minimal, reproducible, example with my use case:
Description
The solution you would like
Describe alternatives you've considered
@app.head
and a helper method for each route, but it's cumbersome:Environment
The text was updated successfully, but these errors were encountered: