1

Using FastAPI I am trying to add a header to the response.

For normal operations this works OK. Even if I raise HTTP Execeptions, I can provide a header.

But when something breaks big, no header is returned.

Update: Since I've received a few suggestions to how to replace the errors, let me clarify: I do not want to make any changes to the response AT ALL, also not to the exception, just add a header. The rest of the response should stay the same.

Example code.

from fastapi import FastAPI, HTTPException, Response
import uvicorn

app = FastAPI()
    
@app.get("/ok", include_in_schema=True)
def a(response: Response):
    response.headers['myheader'] = '123456'
    return {"status": "OK"}

@app.get("/fail", include_in_schema=True)
def b(response: Response):
    raise HTTPException(401, 'Error', headers={'myheader': '123456'})

@app.get("/nok", include_in_schema=True)
def c(response: Response):
    response.headers['myheader'] = '123456'
    raise NotImplementedError("Let's see a header")

uvicorn.run(app=app, host="0.0.0.0", port=9999)

Here the first two endpoints return a header like

content-length: 15 
content-type: application/json 
date: Tue,21 Mar 2023 14:10:32 GMT 
myheader: 123456 
server: uvicorn 

But the last one only has

content-length: 21 
content-type: text/plain; charset=utf-8 
date: Tue,21 Mar 2023 14:11:15 GMT 
server: uvicorn 

How do I add a "myheader" header to a breaking response like the last one?

576i
  • 7,579
  • 12
  • 55
  • 92
  • Have you seen https://fastapi.tiangolo.com/tutorial/handling-errors/ and https://fastapi.tiangolo.com/tutorial/middleware/ ? – MatsLindh Mar 21 '23 at 14:35
  • At @MatsLindh yes and I'm using my own middleware (which alas doesn't catch hard errors like from my example). The tutorial on handling erros didn't teach me to add headers to the original error message. So I can catch it and raise it, but not add a header. – 576i Mar 21 '23 at 15:15
  • Please have a look at related answers [here](https://stackoverflow.com/a/70954531/17865804) and [here](https://stackoverflow.com/a/71682274/17865804) as well. – Chris Mar 22 '23 at 07:14
  • Thanks @Chris, I'll have a look at this. My aim is to catch all errors and to keep all error messages intact, but maybe that's not possible and I have to overwrite the most common messages and just then hope that no other unplanned backend error causes a 500 Internal Server Error – 576i Mar 22 '23 at 10:33
  • Thanks. I implemented a middleware (based on Option 1 from the example) before asking and it did not catch the 500 Internal Server Error (or caught it without letting me see the path) - the reason I'm asking the question is that I'm trying a find a way to extend it. I'll re-try adding the middleware to my simple example and check if it really doesn't catch it at all. – 576i Mar 22 '23 at 13:50
  • Quick update: It's possible to catch all Exceptions in middleware with a try/catch inside of it. – 576i Mar 27 '23 at 21:50

1 Answers1

0

You should be able to do this using an exception handler together with adding headers to an HttpException something along the lines of

from fastapi import FastAPI, HTTPException

app = FastAPI()

@app.exception_handler(NotImplementedError)
async def http_exception_handler(request, exc):
    raise HTTPException(
        status_code=501,
        detail="Item not found",
        headers={"myheader": "123456"},
    )
M.O.
  • 1,712
  • 1
  • 6
  • 18
  • Thanks. This just catches one specific error. The errors I need to catch and re-raise with a header added to the response are all unhandled ones that would lead to a 500 internal server error or a 422 pydanctic validation error of the output. – 576i Mar 21 '23 at 15:17
  • I think you might be able to catch general exceptions by doing `@app.exception_handler(Exception)`, but I'm not sure. You'll have to try it out. – M.O. Mar 21 '23 at 15:29
  • A general exception handler on "Exception" doesn't work. I ended up with a middle ware approach which can capture more. – 576i Mar 27 '23 at 21:47