Utility to create exception handlers in FastAPI in a flexible and standard way
Project description
Exception Handler [ FastAPI Utility ]
This project works together with FastAPI and allows you to create error handlers in a very simple and standard way. Basically it allows you to add (or use the default a function that will be executed when an exception occurs on the server.
This is possible using the FastAPI Exception Handler (actually Starlette) and using a function as a template that receives data such as the request object that was invoked on the route, the exception, the status code that handles that exception, and some 'static' arguments.
Table of Contents
How to use it
Basic
There are several ways to use it, the simplest is to use it with the templates (Callbacks) that come by default. And simply create a list with the pairs of exceptions and status codes.
from fastapi import FastAPI
from ehandler import ExceptionHandlerSetter
app = FastAPI()
handlers = [(ZeroDivisionError, 500), (ValueError, 400)]
ExceptionHandlerSetter(
content_callback_kwargs={"show_error": True, "show_data": True}
).add_handlers(app, handlers)
@app.get("/value_error")
def raise_value_error():
raise ValueError("Invalid value")
@app.get("/division")
def call_external():
return some_func()
@app.get("/uncaught")
def uncaught():
raise Exception("This error is not handled")
def some_func():
print("Trying to do something unless that thing get fails")
return 1 / 0 # This raise a `ZeroDivisionError`
/value_error
- HTTP 400 Bad Request
{
"detail": "Bad Request",
"error": "ValueError",
"message": "Invalid value"
}
/division
- HTTP 500 Internal Server Error
{
"detail": "Internal Server Error",
"error": "ZeroDivisionError",
"message": "division by zero"
}
/uncaught
- HTTP 500 Internal Server Error
Internal Server Error
Explanation
When an error occurs within our server that is not handled (with a try-except
)
the server will respond with a 500 - Internal Server Error
ExceptionHandlerSetter().add_handlers(app, handlers)
Basically create this to
be able to handle specific exceptions (or general if Exception
is handled)
( original example ) :
@app.exception_handler(UnicornException)
async def unicorn_exception_handler(request: Request, exc: UnicornException):
return JSONResponse(
status_code=418,
content={"message": f"Oops! {exc.name} did something. There goes a rainbow..."},
)
But with a dynamic/configurable exception and status code and using a function (callback) as a template, in fact 2 functions/callbacks are used:
- One that parses the content, can take the exception, the request, etc, and create some content with it.
- The other is the function that returns the response, usually just put it
inside a
JSONResponse
.
@app.exception_handler(<ExceptionClass>)
async def <ResponseCallback>(request: Request, content: Any = <content_callback>, status_code: int = <status_code>)
return <ContentCallback>,
Examples
Content callback
Use your own callback to parse the content of the response
import traceback
from fastapi import FastAPI
from ehandler import ExceptionHandlerSetter
app = FastAPI()
def parse_exception(
request: Request,
exception: Exception,
status_code: int,
debug: bool = False,
) -> dict:
content = {"message": "Something went wrong"}
if debug:
content["traceback"] = traceback.format_exc()
return content
handlers = [(Exception, 500)]
ExceptionHandlerSetter(
content_callback=parse_exception
content_callback_kwargs={"debug": True}
).add_handlers(app, handlers)
Add additional data
⚠️ This uses the default implementation from
ehandler.parsers.parse_exception
from fastapi import FastAPI
from ehandler import ExceptionHandlerSetter
from ehandler.utils import add_data
app = FastAPI()
handlers = [(Exception, 500)]
ExceptionHandlerSetter(
content_callback_kwargs={"show_data": True} # If `show_data` is False it won't work
).add_handlers(app, handlers)
@app.get("/exception")
def raise_value_error():
raise add_data(ValueError("Invalid value"), {"user": "user_info"})
/exception
- HTTP 500 Internal Server Error
{
"data": {
"user": "user_info"
},
"detail": "Internal Server Error",
"message": "Invalid value"
}
Change default status_code
from fastapi import FastAPI
from ehandler import ExceptionHandlerSetter
from ehandler.utils import add_code
app = FastAPI()
handlers = [(Exception, 500)]
ExceptionHandlerSetter(force_status_code=False).add_handlers(app, handlers)
@app.get("/exception")
def raise_value_error():
raise add_code(ValueError("Invalid value"), 400)
/exception
- HTTP 400 Bad Request
{
"detail": "Bad Request",
"message": "Invalid value"
}
How to contribute
Prerequisites
Python ^3.9
poetry ^1.1.14
pre-commit ^2.20.0
Install requirements
Install Poetry
Poetry is a tool for dependency management and packaging in Python. It allows you to declare the libraries your project depends on and it will manage (install/update) them for you.
To install poetry you can follow the official documentation on the page according to your operating system. Poetry Installation
Install Pre-Commit
It is a multi-language package manager for pre-commit hooks. You specify a list of hooks you want and pre-commit manages the installation and execution of any hook written in any language before every commit.
To install poetry you can follow the official documentation on the page according to your operating system. Pre-Commit Installation
Install hooks
pre-commit install
Dependencies
Install dependencies
poetry install
You can also follow the documentation of poetry for a better use of this or any questions. Poetry Basic Usage
Add dependency
They are the dependencies that the package needs to work.
poetry add <package>
poetry add fastapi
Add dev dependency
These are the dependencies that you need only for development, for example those that are needed to test the package.
poetry add -D <package>
poetry add -D requests
Tests
Run test
Static test
The analysis or static test is run using pre-commit, you can run a specific analysis using the id, or run all tests
Single test
pre-commit run pylint
⚠️ Pre-commit by default only runs on files modified in stage. If you want to run on all files you can add the
--all-files
flag.
All test
pre-commit run
All files
pre-commit run --all-files
pre-commit run black --all-files
Unittest
poetry run pytest -v
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.