File size: 5,616 Bytes
a152b95
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
# Error Handling in FastAPI

FastAPI provides a structured approach to error handling using HTTP exceptions, custom exception handlers, and validation error customization. Proper error handling ensures clients receive meaningful, consistent error responses.

## HTTPException

The `HTTPException` class is the primary way to return error responses from route handlers:

```python
from fastapi import FastAPI, HTTPException

app = FastAPI()

items = {"widget": {"name": "Widget", "price": 35.99}}

@app.get("/items/{item_id}")
async def read_item(item_id: str):
    if item_id not in items:
        raise HTTPException(
            status_code=404,
            detail="Item not found",
            headers={"X-Error-Code": "ITEM_NOT_FOUND"},
        )
    return items[item_id]
```

When raised, `HTTPException` immediately terminates request processing and returns the specified status code and detail message. The `detail` parameter can be a string, list, or dictionary -- FastAPI serializes it to JSON automatically. The optional `headers` parameter adds custom HTTP headers to the error response.

The default error response format is:

```json
{
    "detail": "Item not found"
}
```

## Custom Exception Handlers

Register custom handlers for any exception type using `@app.exception_handler()`:

```python
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse

class ItemNotFoundException(Exception):
    def __init__(self, item_id: str):
        self.item_id = item_id

app = FastAPI()

@app.exception_handler(ItemNotFoundException)
async def item_not_found_handler(request: Request, exc: ItemNotFoundException):
    return JSONResponse(
        status_code=404,
        content={
            "error": "item_not_found",
            "message": f"Item '{exc.item_id}' does not exist",
            "path": str(request.url),
        },
    )

@app.get("/items/{item_id}")
async def read_item(item_id: str):
    if item_id not in items_db:
        raise ItemNotFoundException(item_id)
    return items_db[item_id]
```

Custom exception handlers receive the `Request` object and the exception instance. They must return a `Response` object (typically `JSONResponse`). You can register handlers for any Python exception class, including built-in exceptions like `ValueError` or `RuntimeError`.

## Handling Validation Errors

FastAPI automatically returns a 422 Unprocessable Entity response when request validation fails. The default response includes detailed error information:

```json
{
    "detail": [
        {
            "type": "int_parsing",
            "loc": ["path", "item_id"],
            "msg": "Input should be a valid integer, unable to parse string as an integer",
            "input": "abc",
            "url": "https://errors.pydantic.dev/2/v/int_parsing"
        }
    ]
}
```

Each error object contains 5 fields: `type` (the error type identifier), `loc` (the location as a list like `["body", "price"]` or `["query", "limit"]`), `msg` (a human-readable message), `input` (the invalid value), and `url` (a link to Pydantic's error documentation).

To customize validation error responses, override the `RequestValidationError` handler:

```python
from fastapi import FastAPI, Request, status
from fastapi.exceptions import RequestValidationError
from fastapi.responses import JSONResponse

app = FastAPI()

@app.exception_handler(RequestValidationError)
async def validation_exception_handler(
    request: Request, exc: RequestValidationError
):
    error_messages = []
    for error in exc.errors():
        field = " -> ".join(str(loc) for loc in error["loc"])
        error_messages.append(f"{field}: {error['msg']}")

    return JSONResponse(
        status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
        content={
            "error": "validation_error",
            "message": "Request validation failed",
            "details": error_messages,
            "error_count": len(exc.errors()),
        },
    )
```

## Overriding Default Exception Handlers

FastAPI has built-in handlers for `HTTPException` and `RequestValidationError`. You can override both:

```python
from fastapi import FastAPI
from fastapi.exceptions import RequestValidationError
from starlette.exceptions import HTTPException as StarletteHTTPException

app = FastAPI()

@app.exception_handler(StarletteHTTPException)
async def http_exception_handler(request: Request, exc: StarletteHTTPException):
    return JSONResponse(
        status_code=exc.status_code,
        content={
            "error": True,
            "status_code": exc.status_code,
            "message": exc.detail,
        },
    )
```

Note: FastAPI's `HTTPException` inherits from Starlette's `HTTPException`. To override the handler for all HTTP exceptions (including those raised by Starlette internals like 404 for missing routes), register the handler for `StarletteHTTPException` rather than FastAPI's version.

## Returning the Request Body in Errors

The `RequestValidationError` object contains the original request body, which can be useful for logging or debugging:

```python
@app.exception_handler(RequestValidationError)
async def validation_handler(request: Request, exc: RequestValidationError):
    return JSONResponse(
        status_code=422,
        content={
            "detail": exc.errors(),
            "body": exc.body,  # The raw request body that failed validation
        },
    )
```

The `exc.body` attribute holds the parsed request body (as a Python object) before validation was applied. This is only available for body validation errors, not for path or query parameter errors.