'Displaying of FastAPI validation errors to end users
I'm looking for some library or example of code to format FastAPI validation messages into human-readable format. E.g. this endpoint:
@app.get("/")
async def hello(name: str):
return {"hello": name}
Will produce the next json output if we miss name
query parameter:
{
"detail":[
{
"loc":[
"query",
"name"
],
"msg":"field required",
"type":"value_error.missing"
}
]
}
So my questions is, how to:
- Transform it into something like "name field is required" (for all kinds of possible errors) to show in toasts.
- Use it to display form validation messages
- Generate forms themselves from api description if it's possible
Solution 1:[1]
FastAPI has a great Exception Handling, so you can customize your exceptions in many ways.
You can raise an HTTPException, HTTPException is a normal Python exception with additional data relevant for APIs. But you can't return it you need to raise it because it's a Python exception
from fastapi import HTTPException
...
@app.get("/")
async def hello(name: str):
if not name:
raise HTTPException(status_code=404, detail="Name field is required")
return {"Hello": name}
By adding name: str
as a query parameter it automatically becomes required so you need to add Optional
from typing import Optional
...
@app.get("/")
async def hello(name: Optional[str] = None):
error = {"Error": "Name field is required"}
if name:
return {"Hello": name}
return error
$ curl 127.0.0.1:8000/?name=imbolc
{"Hello":"imbolc"}
...
$ curl 127.0.0.1:8000
{"Error":"Name field is required"}
But in your case, and i think this is the best way to handling errors in FastAPI overriding the validation_exception_handler
:
from fastapi import FastAPI, Request, status
from fastapi.encoders import jsonable_encoder
from fastapi.exceptions import RequestValidationError
from fastapi.responses import JSONResponse
...
@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(), "Error": "Name field is missing"}),
)
...
@app.get("/")
async def hello(name: str):
return {"hello": name}
You will get a response like this:
$ curl 127.0.0.1:8000
{
"detail":[
{
"loc":[
"query",
"name"
],
"msg":"field required",
"type":"value_error.missing"
}
],
"Error":"Name field is missing"
}
You can customize your content
however if you like:
{
"Error":"Name field is missing",
"Customize":{
"This":"content",
"Also you can":"make it simpler"
}
}
Solution 2:[2]
I reached here with a similar question - and I ended up handling the RequestValidationError
to give back a response where every field is an array of the issues with that field.
The response to your request would become (with a status_code=400)
{
"detail": "Invalid request",
"errors": {"name": ["field required"]}
}
that's quite handy to manage on the frontend for snackbar notifications and flexible enough.
Here's the handler
from collections import defaultdict
from fastapi import status
from fastapi.encoders import jsonable_encoder
from fastapi.responses import JSONResponse
@app.exception_handler(RequestValidationError)
async def custom_form_validation_error(request, exc):
reformatted_message = defaultdict(list)
for pydantic_error in exc.errors():
loc, msg = pydantic_error["loc"], pydantic_error["msg"]
filtered_loc = loc[1:] if loc[0] in ("body", "query", "path") else loc
field_string = ".".join(filtered_loc) # nested fields with dot-notation
reformatted_message[field_string].append(msg)
return JSONResponse(
status_code=status.HTTP_400_BAD_REQUEST,
content=jsonable_encoder(
{"detail": "Invalid request", "errors": reformatted_message}
),
)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 |