I'm currently writing a few end points for an API in fastAPI. I'm defining classes that extend fastapi's HTTPException.
The problem is that HTTPException returns a response body with an attribute called detail which will either be a string or a json structure depending on what object you pass to it as seem below.
{
"detail": {
"msg": "error message here"
}
}
{ "detail": "error message here" }
I would like to override this behavior and let it respond with my own structure.
I'm aware that i can install custom exceptions using the exception handler decorator and have that return a JSONResponse object but this is not what i'm looking for.
You need to use additional exception handler in your root router. here i show an Example:
error_schema.py
from pydantic import BaseModel
class ErrorSchema(BaseModel):
status: int
message: str
exception.py
from typing import Any, Optional, Dict
from fastapi import status
from fastapi import HTTPException
from starlette.responses import JSONResponse
from error_schema import ErrorSchema
async def http_exception_handler(request, exc):
content = ErrorSchema(status=exc.status_code, message=exc.detail).model_dump(mode='json')
return JSONResponse(content, status_code=exc.status_code)
class AuthError(HTTPException):
def __init__(
self, detail: Any = None, headers: Optional[Dict[str, Any]] = None
) -> None:
super().__init__(status.HTTP_403_FORBIDDEN, detail, headers)
class NotFoundError(HTTPException):
def __init__(
self, detail: Any = None, headers: Optional[Dict[str, Any]] = None
) -> None:
super().__init__(status.HTTP_404_NOT_FOUND, detail, headers)
main.py
from fastapi import FastAPI, HTTPException
from exceptions import http_exception_handler, NotFoundError
app = FastAPI()
app.add_exception_handler(HTTPException, http_exception_handler)
# set routers example
@app.get("/"):
raise NotFoundError(detail="NotFound error with your message key")
app.include_router(v1_routers)
Here i define Error Exceptions with their status codes.
You can use AuthError and NotFoundError whole your project just call it like raise NotFoundError(detail="NotFound error with your message key")
here response will be like this:
{
"status": 404,
"message": "NotFound error with your message key",
}
One option is to set the status code corresponding to your exception, and then return a custom response body.
Here is a simple toy example using this approach to workaround the issue at hand:
from fastapi import FastAPI, Response, status
myapp = FastAPI()
@myapp.get("/")
async def app_func(response: Response, myparam: str):
#end point code here
valid_params = ['a', 'b', 'c']
if myparam not in valid_params:
#Customize logic, status code, and returned dict as needed
response.status_code = status.HTTP_400_BAD_REQUEST
return {'message': 'Oh no! I failed (without detail key)'}
response.status_code = status.HTTP_200_OK
return {'message': 'Yay! I succeeded!'}
A full list of available status codes can be found here.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With