еще правки
This commit is contained in:
parent
2f5cb21dc0
commit
5210f1d6f7
@ -1,4 +1,5 @@
|
|||||||
from fastapi import FastAPI, HTTPException, status
|
from fastapi import FastAPI, HTTPException, status
|
||||||
|
from fastapi.exceptions import RequestValidationError
|
||||||
from fastapi.responses import JSONResponse
|
from fastapi.responses import JSONResponse
|
||||||
from sqlalchemy.exc import IntegrityError, OperationalError, SQLAlchemyError, DBAPIError
|
from sqlalchemy.exc import IntegrityError, OperationalError, SQLAlchemyError, DBAPIError
|
||||||
|
|
||||||
@ -94,7 +95,28 @@ def map_http_exception(exc: HTTPException) -> tuple[int, int, str, str]:
|
|||||||
return status_code, status_code, message, ""
|
return status_code, status_code, message, ""
|
||||||
|
|
||||||
|
|
||||||
|
def map_request_validation_error(exc: RequestValidationError) -> tuple[int, int, str, str]:
|
||||||
|
status_code = status.HTTP_422_UNPROCESSABLE_ENTITY
|
||||||
|
errors = exc.errors()
|
||||||
|
if not errors:
|
||||||
|
return status_code, status_code, "Validation error", ""
|
||||||
|
|
||||||
|
first_error = errors[0]
|
||||||
|
message = str(first_error.get("msg") or "Validation error")
|
||||||
|
loc = first_error.get("loc") or ()
|
||||||
|
field = ".".join(str(part) for part in loc if part not in ("body", "query", "path", "header", "cookie"))
|
||||||
|
return status_code, status_code, message, field
|
||||||
|
|
||||||
|
|
||||||
def register_exception_handlers(app: FastAPI) -> None:
|
def register_exception_handlers(app: FastAPI) -> None:
|
||||||
|
@app.exception_handler(RequestValidationError)
|
||||||
|
async def request_validation_exception_handler(request, exc: RequestValidationError):
|
||||||
|
status_code, code, message, field = map_request_validation_error(exc)
|
||||||
|
return JSONResponse(
|
||||||
|
status_code=status_code,
|
||||||
|
content=_error_payload(code, message, field=field),
|
||||||
|
)
|
||||||
|
|
||||||
@app.exception_handler(HTTPException)
|
@app.exception_handler(HTTPException)
|
||||||
async def http_exception_handler(request, exc: HTTPException):
|
async def http_exception_handler(request, exc: HTTPException):
|
||||||
status_code, code, message, field = map_http_exception(exc)
|
status_code, code, message, field = map_http_exception(exc)
|
||||||
|
|||||||
@ -29,6 +29,10 @@ def _make_app() -> FastAPI:
|
|||||||
exc.orig = Exception("budget_form #99 не существует")
|
exc.orig = Exception("budget_form #99 не существует")
|
||||||
raise exc
|
raise exc
|
||||||
|
|
||||||
|
@app.get("/form/{form_id}")
|
||||||
|
async def form_by_id(form_id: int):
|
||||||
|
return {"form_id": form_id}
|
||||||
|
|
||||||
return app
|
return app
|
||||||
|
|
||||||
|
|
||||||
@ -66,3 +70,15 @@ def test_sqlalchemy_exception_returns_structured_payload():
|
|||||||
"field": "",
|
"field": "",
|
||||||
"message": "budget_form #99 не существует",
|
"message": "budget_form #99 не существует",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def test_request_validation_422_returns_structured_payload():
|
||||||
|
client = TestClient(_make_app())
|
||||||
|
response = client.get("/form/not-int")
|
||||||
|
|
||||||
|
assert response.status_code == status.HTTP_422_UNPROCESSABLE_ENTITY
|
||||||
|
assert response.json() == {
|
||||||
|
"code": status.HTTP_422_UNPROCESSABLE_ENTITY,
|
||||||
|
"field": "form_id",
|
||||||
|
"message": "Input should be a valid integer, unable to parse string as an integer",
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user