Fastapi: Problems with customizing pydantic error messages[QUESTION]

Created on 22 Mar 2020  ·  3Comments  ·  Source: tiangolo/fastapi

First check

  • [ ] I used the GitHub search to find a similar issue and didn't find it.
  • [ ] I searched the FastAPI documentation, with the integrated search.
  • [ ] I already searched in Google "How to X in FastAPI" and didn't find any information.

Description

I want to customize the wrong version of pydantic, but it doesn't work。

I would like to ask what I should do。


from pydantic import BaseModel, ValidationError
class Model(BaseModel):
v: str

# def __init__(self,v =None):
#     print('被调用了 外部类')
class Config:
    max_anystr_length = 1
    error_msg_templates = {
        'value_error.any_str.max_length': 'max_length:{limit_value}',
    }

@app.post("/items/")
async def create_item(item: Model):
return item


error_msg_templates definition does not work!

Thank you very much

How can I [...]?

Is it possible to [...]?

Additional context

Add any other context or screenshots about the feature request here.

question

Most helpful comment

This one is actually interesting. Looks like pydantic's internal error_dict() function is overriding the previous custom error message and falls back to default because it did not get a valid model from FastAPI. It's being used publicly but it's mostly a pydantic internal function, and I would not blame pydantic here. I am not sure if FastAPI can use pydantic's internal more wisely somehow.

https://github.com/samuelcolvin/pydantic/blob/d495710303c7716f0a54281b86a7c1c81930c223/pydantic/error_wrappers.py#L109-L111

A more self-contained testcase:

from pydantic import BaseModel, ValidationError
from fastapi import FastAPI
from fastapi.exception_handlers import request_validation_exception_handler
from fastapi.exceptions import RequestValidationError
from starlette.requests import Request
from starlette.responses import Response

class Model(BaseModel):
    v: str
    class Config:
        max_anystr_length = 1
        error_msg_templates = {
            'value_error.any_str.max_length': 'max_length:{limit_value}',
        }

app = FastAPI()

@app.exception_handler(RequestValidationError)
async def http_exception_accept_handler(request: Request, exc: RequestValidationError) -> Response:
    print(exc.raw_errors)
    print(exc)
    return await request_validation_exception_handler(request, exc)

@app.post("/")
async def create_item(item: Model):
    return item

try:
    Model.validate({'v':'x' * 20})
except ValidationError as e:
    print(e)

All 3 comments

This one is actually interesting. Looks like pydantic's internal error_dict() function is overriding the previous custom error message and falls back to default because it did not get a valid model from FastAPI. It's being used publicly but it's mostly a pydantic internal function, and I would not blame pydantic here. I am not sure if FastAPI can use pydantic's internal more wisely somehow.

https://github.com/samuelcolvin/pydantic/blob/d495710303c7716f0a54281b86a7c1c81930c223/pydantic/error_wrappers.py#L109-L111

A more self-contained testcase:

from pydantic import BaseModel, ValidationError
from fastapi import FastAPI
from fastapi.exception_handlers import request_validation_exception_handler
from fastapi.exceptions import RequestValidationError
from starlette.requests import Request
from starlette.responses import Response

class Model(BaseModel):
    v: str
    class Config:
        max_anystr_length = 1
        error_msg_templates = {
            'value_error.any_str.max_length': 'max_length:{limit_value}',
        }

app = FastAPI()

@app.exception_handler(RequestValidationError)
async def http_exception_accept_handler(request: Request, exc: RequestValidationError) -> Response:
    print(exc.raw_errors)
    print(exc)
    return await request_validation_exception_handler(request, exc)

@app.post("/")
async def create_item(item: Model):
    return item

try:
    Model.validate({'v':'x' * 20})
except ValidationError as e:
    print(e)

Figured out some workaround:

@app.exception_handler(RequestValidationError)
async def http_exception_accept_handler(request: Request, exc: RequestValidationError) -> Response:
    raw_errors = exc.raw_errors
    error_wrapper: ErrorWrapper = raw_errors[0]
    validation_error: ValidationError = error_wrapper.exc
    overwritten_errors = validation_error.errors()
    return JSONResponse(status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
                        content={"detail": jsonable_encoder(overwritten_errors)},
                        )

Now output will be as expected

I got the same Problem also!
I tested the same code in pydantic, it's OK, but in the environment of fastAPI, it returned the default error msg.

from pydantic import BaseModel, ValidationError

class UserModel(BaseModel):
    name: str
    age: int
    class Config:
        error_msg_templates = {"type_error.integer":"The param must be an integer!"}

try:
    d = {"name":'aaa', "age":"ee"}
    u = UserModel(**d)
    print(u)
except ValidationError as e:
    print(e)

# age
#  The param must be an integer! (type=type_error.integer)

this is the code with fastAPI

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class User(BaseModel):
    name: str
    age: int    
    class Config:
        error_msg_templates = {"type_error.integer":"The param must be an integer!"}


@app.post('/')
def index(u:User):
    return u

And the error msg is:

{
    "detail": [
        {
            "loc": [
                "body",
                "u",
                "age"
            ],
            "msg": "value is not a valid integer",
            "type": "type_error.integer"
        }
    ]
}
Was this page helpful?
0 / 5 - 0 ratings