-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Nice custom error wrapper for pydanic issues. Adds a "message" field …
…with user readable errors, while keeping the source_errors as well
- Loading branch information
Showing
4 changed files
with
105 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
from fastapi import FastAPI, Request, status | ||
from fastapi.exceptions import RequestValidationError | ||
from fastapi.responses import JSONResponse | ||
|
||
|
||
def connect_custom_errors(app: FastAPI): | ||
@app.exception_handler(RequestValidationError) | ||
async def validation_exception_handler( | ||
request: Request, exc: RequestValidationError | ||
): | ||
# Write user friendly error messages | ||
error_messages = [] | ||
for error in exc.errors(): | ||
field = error["loc"][-1] # Get the field name | ||
message = error["msg"] | ||
error_messages.append(f"{field.capitalize()}: {message}") | ||
|
||
return JSONResponse( | ||
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, | ||
content={ | ||
"message": ".\n".join(error_messages), | ||
"source_errors": exc.errors(), | ||
}, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
import pytest | ||
from fastapi import FastAPI | ||
from fastapi.testclient import TestClient | ||
from pydantic import BaseModel, Field | ||
|
||
from libs.studio.kiln_studio.custom_errors import connect_custom_errors | ||
|
||
|
||
@pytest.fixture | ||
def app(): | ||
app = FastAPI() | ||
connect_custom_errors(app) | ||
|
||
class Item(BaseModel): | ||
name: str = Field(..., min_length=3) | ||
price: float = Field(..., gt=0) | ||
|
||
@app.post("/items") | ||
async def create_item(item: Item): | ||
return item | ||
|
||
return app | ||
|
||
|
||
@pytest.fixture | ||
def client(app): | ||
return TestClient(app) | ||
|
||
|
||
def test_validation_error_single_field(client): | ||
response = client.post("/items", json={"name": "ab", "price": 10}) | ||
assert response.status_code == 422 | ||
assert response.json() == { | ||
"message": "Name: String should have at least 3 characters", | ||
"source_errors": [ | ||
{ | ||
"type": "string_too_short", | ||
"loc": ["body", "name"], | ||
"msg": "String should have at least 3 characters", | ||
"input": "ab", | ||
"ctx": {"min_length": 3}, | ||
} | ||
], | ||
} | ||
|
||
|
||
def test_validation_error_multiple_fields(client): | ||
response = client.post("/items", json={"name": "ab", "price": -5}) | ||
assert response.status_code == 422 | ||
assert response.json() == { | ||
"message": "Name: String should have at least 3 characters.\nPrice: Input should be greater than 0", | ||
"source_errors": [ | ||
{ | ||
"type": "string_too_short", | ||
"loc": ["body", "name"], | ||
"msg": "String should have at least 3 characters", | ||
"input": "ab", | ||
"ctx": {"min_length": 3}, | ||
}, | ||
{ | ||
"type": "greater_than", | ||
"loc": ["body", "price"], | ||
"msg": "Input should be greater than 0", | ||
"input": -5, | ||
"ctx": {"gt": 0}, | ||
}, | ||
], | ||
} | ||
|
||
|
||
def test_valid_input(client): | ||
response = client.post("/items", json={"name": "abc", "price": 10}) | ||
assert response.status_code == 200 | ||
assert response.json() == {"name": "abc", "price": 10} |