diff --git a/fastapi/routing.py b/fastapi/routing.py index 36acb6b89d..8fc7e3a465 100644 --- a/fastapi/routing.py +++ b/fastapi/routing.py @@ -890,6 +890,8 @@ class APIRoute(routing.Route): if methods is None: methods = ["GET"] self.methods: set[str] = {method.upper() for method in methods} + if "GET" in self.methods: + self.methods.add("HEAD") if isinstance(generate_unique_id_function, DefaultPlaceholder): current_generate_unique_id: Callable[[APIRoute], str] = ( generate_unique_id_function.value diff --git a/tests/test_auto_head.py b/tests/test_auto_head.py new file mode 100644 index 0000000000..485a6e8bc4 --- /dev/null +++ b/tests/test_auto_head.py @@ -0,0 +1,57 @@ +"""Test that HEAD requests are automatically supported for GET routes (issue #1773).""" +from fastapi import FastAPI +from fastapi.testclient import TestClient + + +def test_head_for_get_route(): + """HEAD request on a GET route should return 200, not 405.""" + app = FastAPI() + + @app.get("/") + def read_root(): + return {"Hello": "World"} + + client = TestClient(app) + response = client.head("/") + assert response.status_code == 200 + assert response.headers.get("content-type") is not None + + +def test_head_for_get_route_with_path(): + """HEAD request on a parameterized GET route should work.""" + app = FastAPI() + + @app.get("/items/{item_id}") + def read_item(item_id: int): + return {"item_id": item_id} + + client = TestClient(app) + response = client.head("/items/42") + assert response.status_code == 200 + + +def test_head_not_auto_added_for_post(): + """POST routes should NOT automatically support HEAD.""" + app = FastAPI() + + @app.post("/items/") + def create_item(): + return {"created": True} + + client = TestClient(app) + response = client.head("/items/") + assert response.status_code == 405 + + +def test_head_response_has_no_body(): + """HEAD response should have no body content.""" + app = FastAPI() + + @app.get("/") + def read_root(): + return {"Hello": "World"} + + client = TestClient(app) + response = client.head("/") + assert response.status_code == 200 + assert response.content == b""