Skip to content

#225: Set a Response Header With FastAPI

While improving the HTTP status codes, I noticed that there should be a header pointing to the newly created task. Let us add that header to our FastAPI application.

Extend the create task test

In our test_create_task() method we can access the header of the response and check if it contains a value for the location:

def test_create_task():
    data = {
        "name": "A first task",
        "priority": 5,
        "due_date": str(date.today() + timedelta(days=1)),
        "done": False
    }

    response = client.post("/api/todo/", json=data)
    assert response.status_code == 201
    result = response.json()
    # ...
    assert f"http://testserver/api/todo/{result['id']}" == response.headers['location']

Since our test client always runs against the test server, we can be explicit with the URL we expect.

Add the header in the endpoint

In the endpoint it takes a bit more work. First, we need to inject the Response into our endpoint. That allows us to dynamically fetch the base URL of our server, without trying to access that value through private methods in FastAPI.

Then we can create a dictionary with our header values. For our use case the location should point to the endpoint that shows us the details of the newly created task.

As a final step we need to pass our headers dictionary to the JSONResponse:

1
2
3
4
5
6
7
@app.post("/api/todo")
async def create_task(task: TaskInput, request: Request) -> TaskOutput:
    result = db.add(task)
    headers = {"Location": f"{request.base_url}api/todo/{result.id}"}
    return JSONResponse(content=jsonable_encoder(result), 
                        status_code=status.HTTP_201_CREATED,
                        headers=headers)

Next

Setting headers in FastAPI is not a big deal. All we need to do is to create a dictionary and put it into our response. Next week we revisit our Swagger documentation and fine-tune the OpenAPI specification.