简体   繁体   中英

Is it possible to change the pydantic error messages in fastAPI?

In the FastAPI framework, the pydantic error messages are showing like below.

{"detail": [
{
    "loc": [
        "body",
        "location",
        "name"
    ],
    "msg": "field required",
    "type": "value_error.missing"
},
{
    "loc": [
        "body",
        "location",
        "name12"
    ],
    "msg": "extra fields not permitted",
    "type": "value_error.extra"
}
]
}

I want to send a simple message: {"field-name":"error message"} .

In Pydantic document they mentioned like, create a model instance in the try: except blocks and construct the error message in the except block. But in fast API, model instance created by fastapi itself, for example, if I write an URL like below

@router.post("/", response_model=DataModelOut)
async def create_location(location: schemas.LocationIn, user: str = Depends(get_current_user) ):
return model.save(location,user)

Here the location instance created by fastapi itself is the problem.

Is there any way to construct the error message?

Actually this error messages coming from fastapi.exceptions , You can achieve that by overriding the custom exceptions,

Imagine i have simple app like this:

from fastapi import Request, status
from fastapi.encoders import jsonable_encoder
from fastapi.exceptions import RequestValidationError
from fastapi.responses import JSONResponse
from pydantic import BaseModel

@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(),
                "body": exc.body,
                 "your_additional_errors": {"Will be": "Inside", "This":" Error message"}}),
    )

class Item(BaseModel):
    title: str
    size: int

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

If i send values invalid values to my Request body

{
 "title": 22,
 "size": "hehe"
}

Now the error will be more customized:

{
  "detail": [
    {
      "loc": [
        "body",
        "size"
      ],
      "msg": "value is not a valid integer",
      "type": "type_error.integer"
    }
  ],
  "body": {
    "title": 22,
    "size": "hehe"
  },
  "your_additional_errors": {
    "Will be": "Inside the",
    "Error": "Message"
  }
}

You can change the content of exception, everything is up to you.

I am writing a middle ware for it.

async def genrange(s):
    import json
    s = json.loads(s)
    yield json.dumps({"message":{k.get("loc")[-1]:k.get("msg") for k in s['detail']},
        "id":None})

@app.middleware("http")
async def add_process_time_header(request: Request, call_next):
    response = await call_next(request)
    status_code = response.status_code
    if status_code >=300:
        async for i in response.body_iterator:
            data = genrange(i)
        response.body_iterator = data
    return response

I'm not sure you'll like my answer better than the other answers. You can create a custom pydantic, with diffrent error messages. Kinda overkill, but could solve you a specific problem. In this example, I am changing the error message, when I insert an unpermitted HttpUrlSceme.

class UrlSchemePermittedError(errors.UrlError):
    code = 'url.scheme'
    msg_template = 'URL scheme not cool'

    def __init__(self, allowed_schemes: Set[str]):
        super().__init__(allowed_schemes=allowed_schemes)

class AnyHttpUrlDirrentMessage(AnyUrl):
    allowed_schemes = {'http', 'https'}
    @classmethod
    def validate_parts(cls, parts: Dict[str, str]) -> Dict[str, str]:
        """
        A method used to validate parts of an URL.
        Could be overridden to set default values for parts if missing
        """
        scheme = parts['scheme']
        if scheme is None:
            raise errors.UrlSchemeError()

        if cls.allowed_schemes and scheme.lower() not in cls.allowed_schemes:
            raise UrlSchemePermittedError(cls.allowed_schemes)

        port = parts['port']
        if port is not None and int(port) > 65_535:
            raise errors.UrlPortError()

        user = parts['user']
        if cls.user_required and user is None:
            raise errors.UrlUserInfoError()

        return parts

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM