2018-09-04 10:52:29 +00:00
|
|
|
|
2018-11-08 11:59:15 +00:00
|
|
|
Starlette allows you to install custom exception handlers to deal with
|
|
|
|
how you return responses when errors or handled exceptions occur.
|
2018-09-04 10:52:29 +00:00
|
|
|
|
|
|
|
```python
|
2018-11-08 11:59:15 +00:00
|
|
|
from starlette.applications import Starlette
|
2022-01-26 15:06:15 +00:00
|
|
|
from starlette.exceptions import HTTPException
|
|
|
|
from starlette.requests import Request
|
2018-11-08 11:59:15 +00:00
|
|
|
from starlette.responses import HTMLResponse
|
2018-09-04 10:52:29 +00:00
|
|
|
|
|
|
|
|
2018-11-08 11:59:15 +00:00
|
|
|
HTML_404_PAGE = ...
|
|
|
|
HTML_500_PAGE = ...
|
2018-09-04 10:52:29 +00:00
|
|
|
|
|
|
|
|
2022-01-26 15:06:15 +00:00
|
|
|
async def not_found(request: Request, exc: HTTPException):
|
2019-01-21 09:29:34 +00:00
|
|
|
return HTMLResponse(content=HTML_404_PAGE, status_code=exc.status_code)
|
2018-09-04 10:52:29 +00:00
|
|
|
|
2022-01-26 15:06:15 +00:00
|
|
|
async def server_error(request: Request, exc: HTTPException):
|
2019-01-21 09:29:34 +00:00
|
|
|
return HTMLResponse(content=HTML_500_PAGE, status_code=exc.status_code)
|
2019-11-13 12:25:18 +00:00
|
|
|
|
|
|
|
|
|
|
|
exception_handlers = {
|
|
|
|
404: not_found,
|
|
|
|
500: server_error
|
|
|
|
}
|
|
|
|
|
|
|
|
app = Starlette(routes=routes, exception_handlers=exception_handlers)
|
2018-09-04 10:52:29 +00:00
|
|
|
```
|
|
|
|
|
2018-11-08 11:59:15 +00:00
|
|
|
If `debug` is enabled and an error occurs, then instead of using the installed
|
|
|
|
500 handler, Starlette will respond with a traceback response.
|
2018-09-04 10:52:29 +00:00
|
|
|
|
2018-11-08 11:59:15 +00:00
|
|
|
```python
|
2019-11-13 12:25:18 +00:00
|
|
|
app = Starlette(debug=True, routes=routes, exception_handlers=exception_handlers)
|
2018-09-04 10:52:29 +00:00
|
|
|
```
|
|
|
|
|
2018-11-08 11:59:15 +00:00
|
|
|
As well as registering handlers for specific status codes, you can also
|
|
|
|
register handlers for classes of exceptions.
|
2018-09-04 10:52:29 +00:00
|
|
|
|
2018-11-08 11:59:15 +00:00
|
|
|
In particular you might want to override how the built-in `HTTPException` class
|
|
|
|
is handled. For example, to use JSON style responses:
|
2018-09-04 10:52:29 +00:00
|
|
|
|
2018-11-08 11:59:15 +00:00
|
|
|
```python
|
2022-01-26 15:06:15 +00:00
|
|
|
async def http_exception(request: Request, exc: HTTPException):
|
2018-11-08 11:59:15 +00:00
|
|
|
return JSONResponse({"detail": exc.detail}, status_code=exc.status_code)
|
2019-11-13 12:25:18 +00:00
|
|
|
|
|
|
|
exception_handlers = {
|
|
|
|
HTTPException: http_exception
|
|
|
|
}
|
2018-11-08 11:59:15 +00:00
|
|
|
```
|
2018-09-04 10:52:29 +00:00
|
|
|
|
2022-01-26 15:06:15 +00:00
|
|
|
The `HTTPException` is also equipped with the `headers` argument. Which allows the propagation
|
|
|
|
of the headers to the response class:
|
|
|
|
|
|
|
|
```python
|
|
|
|
async def http_exception(request: Request, exc: HTTPException):
|
|
|
|
return JSONResponse(
|
|
|
|
{"detail": exc.detail},
|
|
|
|
status_code=exc.status_code,
|
|
|
|
headers=exc.headers
|
|
|
|
)
|
|
|
|
```
|
|
|
|
|
2022-09-05 12:31:59 +00:00
|
|
|
You might also want to override how `WebSocketException` is handled:
|
|
|
|
|
|
|
|
```python
|
|
|
|
async def websocket_exception(websocket: WebSocket, exc: WebSocketException):
|
|
|
|
await websocket.close(code=1008)
|
|
|
|
|
|
|
|
exception_handlers = {
|
|
|
|
WebSocketException: websocket_exception
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2018-11-08 11:59:15 +00:00
|
|
|
## Errors and handled exceptions
|
2018-09-04 10:52:29 +00:00
|
|
|
|
2018-11-08 11:59:15 +00:00
|
|
|
It is important to differentiate between handled exceptions and errors.
|
2018-09-04 10:52:29 +00:00
|
|
|
|
2018-11-08 11:59:15 +00:00
|
|
|
Handled exceptions do not represent error cases. They are coerced into appropriate
|
|
|
|
HTTP responses, which are then sent through the standard middleware stack. By default
|
|
|
|
the `HTTPException` class is used to manage any handled exceptions.
|
2018-09-04 10:52:29 +00:00
|
|
|
|
2018-11-08 11:59:15 +00:00
|
|
|
Errors are any other exception that occurs within the application. These cases
|
|
|
|
should bubble through the entire middleware stack as exceptions. Any error
|
|
|
|
logging middleware should ensure that it re-raises the exception all the
|
|
|
|
way up to the server.
|
2018-09-04 10:52:29 +00:00
|
|
|
|
2022-02-01 14:08:24 +00:00
|
|
|
In practical terms, the error handled used is `exception_handler[500]` or `exception_handler[Exception]`.
|
|
|
|
Both keys `500` and `Exception` can be used. See below:
|
|
|
|
|
|
|
|
```python
|
|
|
|
async def handle_error(request: Request, exc: HTTPException):
|
|
|
|
# Perform some logic
|
|
|
|
return JSONResponse({"detail": exc.detail}, status_code=exc.status_code)
|
|
|
|
|
|
|
|
exception_handlers = {
|
|
|
|
Exception: handle_error # or "500: handle_error"
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
It's important to notice that in case a [`BackgroundTask`](https://www.starlette.io/background/) raises an exception,
|
|
|
|
it will be handled by the `handle_error` function, but at that point, the response was already sent. In other words,
|
|
|
|
the response created by `handle_error` will be discarded. In case the error happens before the response was sent, then
|
|
|
|
it will use the response object - in the above example, the returned `JSONResponse`.
|
|
|
|
|
2018-11-08 11:59:15 +00:00
|
|
|
In order to deal with this behaviour correctly, the middleware stack of a
|
|
|
|
`Starlette` application is configured like this:
|
2018-09-04 10:52:29 +00:00
|
|
|
|
2018-11-08 11:59:15 +00:00
|
|
|
* `ServerErrorMiddleware` - Returns 500 responses when server errors occur.
|
|
|
|
* Installed middleware
|
|
|
|
* `ExceptionMiddleware` - Deals with handled exceptions, and returns responses.
|
|
|
|
* Router
|
|
|
|
* Endpoints
|
2018-09-04 10:52:29 +00:00
|
|
|
|
|
|
|
## HTTPException
|
|
|
|
|
|
|
|
The `HTTPException` class provides a base class that you can use for any
|
2018-11-08 11:59:15 +00:00
|
|
|
handled exceptions. The `ExceptionMiddleware` implementation defaults to
|
|
|
|
returning plain-text HTTP responses for any `HTTPException`.
|
2018-09-04 10:52:29 +00:00
|
|
|
|
2022-01-26 15:06:15 +00:00
|
|
|
* `HTTPException(status_code, detail=None, headers=None)`
|
2018-11-08 11:59:15 +00:00
|
|
|
|
|
|
|
You should only raise `HTTPException` inside routing or endpoints. Middleware
|
|
|
|
classes should instead just return appropriate responses directly.
|
2022-09-05 12:31:59 +00:00
|
|
|
|
|
|
|
## WebSocketException
|
|
|
|
|
|
|
|
You can use the `WebSocketException` class to raise errors inside of WebSocket endpoints.
|
|
|
|
|
|
|
|
* `WebSocketException(code=1008, reason=None)`
|
|
|
|
|
|
|
|
You can set any code valid as defined [in the specification](https://tools.ietf.org/html/rfc6455#section-7.4.1).
|