Exceptions
Starlette allows you to install custom exception handlers to deal withhow you return responses when errors or handled exceptions occur.
fromstarlette.applicationsimportStarlettefromstarlette.exceptionsimportHTTPExceptionfromstarlette.requestsimportRequestfromstarlette.responsesimportHTMLResponseHTML_404_PAGE=...HTML_500_PAGE=...asyncdefnot_found(request:Request,exc:HTTPException):returnHTMLResponse(content=HTML_404_PAGE,status_code=exc.status_code)asyncdefserver_error(request:Request,exc:HTTPException):returnHTMLResponse(content=HTML_500_PAGE,status_code=exc.status_code)exception_handlers={404:not_found,500:server_error}app=Starlette(routes=routes,exception_handlers=exception_handlers)Ifdebug is enabled and an error occurs, then instead of using the installed500 handler, Starlette will respond with a traceback response.
app=Starlette(debug=True,routes=routes,exception_handlers=exception_handlers)As well as registering handlers for specific status codes, you can alsoregister handlers for classes of exceptions.
In particular you might want to override how the built-inHTTPException classis handled. For example, to use JSON style responses:
asyncdefhttp_exception(request:Request,exc:HTTPException):returnJSONResponse({"detail":exc.detail},status_code=exc.status_code)exception_handlers={HTTPException:http_exception}TheHTTPException is also equipped with theheaders argument. Which allows the propagationof the headers to the response class:
asyncdefhttp_exception(request:Request,exc:HTTPException):returnJSONResponse({"detail":exc.detail},status_code=exc.status_code,headers=exc.headers)You might also want to override howWebSocketException is handled:
asyncdefwebsocket_exception(websocket:WebSocket,exc:WebSocketException):awaitwebsocket.close(code=1008)exception_handlers={WebSocketException:websocket_exception}Errors and handled exceptions
It is important to differentiate between handled exceptions and errors.
Handled exceptions do not represent error cases. They are coerced into appropriateHTTP responses, which are then sent through the standard middleware stack. By defaulttheHTTPException class is used to manage any handled exceptions.
Errors are any other exception that occurs within the application. These casesshould bubble through the entire middleware stack as exceptions. Any errorlogging middleware should ensure that it re-raises the exception all theway up to the server.
In practical terms, the error handled used isexception_handler[500] orexception_handler[Exception].Both keys500 andException can be used. See below:
asyncdefhandle_error(request:Request,exc:HTTPException):# Perform some logicreturnJSONResponse({"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 aBackgroundTask raises an exception,it will be handled by thehandle_error function, but at that point, the response was already sent. In other words,the response created byhandle_error will be discarded. In case the error happens before the response was sent, thenit will use the response object - in the above example, the returnedJSONResponse.
In order to deal with this behaviour correctly, the middleware stack of aStarlette application is configured like this:
ServerErrorMiddleware- Returns 500 responses when server errors occur.- Installed middleware
ExceptionMiddleware- Deals with handled exceptions, and returns responses.- Router
- Endpoints
HTTPException
TheHTTPException class provides a base class that you can use for any handled exceptions.TheExceptionMiddleware implementation defaults to returning plain-text HTTP responses for anyHTTPException.
HTTPException(status_code, detail=None, headers=None)
You should only raiseHTTPException inside routing or endpoints.Middleware classes should instead just return appropriate responses directly.
You can use anHTTPException on a WebSocket endpoint. In case it's raised beforewebsocket.accept()the connection is not upgraded to a WebSocket connection, and the proper HTTP response is returned.
fromstarlette.applicationsimportStarlettefromstarlette.exceptionsimportHTTPExceptionfromstarlette.routingimportWebSocketRoutefromstarlette.websocketsimportWebSocketasyncdefwebsocket_endpoint(websocket:WebSocket):raiseHTTPException(status_code=400,detail="Bad request")app=Starlette(routes=[WebSocketRoute("/ws",websocket_endpoint)])WebSocketException
You can use theWebSocketException class to raise errors inside of WebSocket endpoints.
WebSocketException(code=1008, reason=None)
You can set any code valid as definedin the specification.