pythonjsonfastapipydantic

How to customize error response in FastAPI?


I have the following FastAPI backend:

from fastapi import FastAPI

app = FastAPI

class Demo(BaseModel):
    content: str = None
    
@app.post("/demo")
async def demoFunc(d:Demo):
    return d.content

The issue is that when I send a request to this API with extra data like:

data = {"content":"some text here"}aaaa

or

data = {"content":"some text here"aaaaaa}

resp = requests.post(url, json=data)

it throws an error with status code 422 unprocessable entity error with Actual("some text here") and Extra("aaaaa") data in the return field in case of data = {"content":"some text here"}aaaa:

{
  "detail": [
    {
      "loc": [
        "body",
        47
      ],
      "msg": "Extra data: line 4 column 2 (char 47)",
      "type": "value_error.jsondecode",
      "ctx": {
        "msg": "Extra data",
        "doc": "{\n  \"content\": \"some text here\"}aaaaa",
        "pos": 47,
        "lineno": 4,
        "colno": 2
      }
    }
  ]
}

I tried to put the line app=FastAPI() in a try-catch block, however, it doesn't work. Is there any way I can handle this issue with own response instead of the above mentioned auto response? Something like this:

{"error": {"message": "Invalid JSON body"},
                         "status": 0}

Solution

  • You are passing an invalid JSON, and hence, the server correctly responds with the 422 Unprocessable Entity error. Your test client shouldn't be able to run at all, without throwing an invalid syntax error. So, I'm guessing you posted the request through the interactive autodocs provided by Swagger UI at /docs, and received the relevant 422 error.

    If what you actually want is to handle the error, in order to customize the error or something, you can override the request validation exception handler, as described in the documentation (have a look at this discussion, as well as this answer and this answer that demonstrates how to customize the RequestValidationError for specific routes only).

    Working Example:

    from fastapi import FastAPI, Body, Request, status
    from fastapi.encoders import jsonable_encoder
    from fastapi.exceptions import RequestValidationError
    from fastapi.responses import JSONResponse
    from pydantic import BaseModel
    
    app = FastAPI()
    
    
    class Demo(BaseModel):
        content: str = None
    
    
    @app.exception_handler(RequestValidationError)
    async def validation_exception_handler(request: Request, exc: RequestValidationError):
        return JSONResponse(
            status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
            content=jsonable_encoder({"detail": exc.errors(),  # optionally include the errors
                    "body": exc.body,
                     "custom msg": {"Your error message"}}),
        )
    
    
    @app.post("/demo")
    async def some_func(d: Demo):
        return d.content
    

    Or, you could also return a PlainTextResponse with a custom message:

    from fastapi.responses import PlainTextResponse
    
    @app.exception_handler(RequestValidationError)
    async def validation_exception_handler(request, exc):
        return PlainTextResponse(str(exc), status_code=422)