aiohttp-catcher
aiohttp-catcher is a centralized error handler for aiohttp servers. It enables consistant error handlling across your web server or API, so your code can raise Python exceptions that will be handled however you want them to.
Quickstart
from aiohttp import web
from aiohttp_catcher import catch, Catcher
async def hello(request):
division = 1 / 0
return web.Response(text=f"1 / 0 = {division}")
async def main():
# Add a catcher:
catcher = Catcher()
# Register error-handling scenarios:
await catcher.add_scenario(
catch(ZeroDivisionError).with_status_code(400).and_return("Zero division makes zero sense")
)
# Register your catcher as an aiohttp middleware:
app = web.Application(middlewares=[catcher.middleware])
app.add_routes([web.get("/divide-by-zero", hello)])
web.run_app(app)
Making a request to /divide-by-zero will return a 400 status code with the following body:
{"code": 400, "message": "Zero division makes zero sense"}
Key Features
Return a Constant
In case you want some exceptions to return a constant message across your application, you can do
so by using the .and_return("some value") method:
await catcher.add_scenario(
catch(ZeroDivisionError).with_status_code(400).and_return("Zero division makes zero sense")
)
Stringify the Exception
In some cases, you would want to return a stringified version of your exception, should it entail user-friendly information.
class EntityNotFound(Exception):
def __init__(self, entity_id, *args, **kwargs):
super(EntityNotFound, self).__init__(*args, **kwargs)
self.entity_id = entity_id
def __str__(self):
return f"Entity {self.entity_id} could not be found"
@routes.get("/user/{user_id}")
async def get_user(request):
user_id = request.match_info.get("user_id")
if user_id not in user_db:
raise EntityNotFound(entity_id=user_id)
return user_db[user_id]
# Your catcher can be directed to stringify particular exceptions:
await catcher.add_scenario(
catch(EntityNotFound).with_status_code(404).and_stringify()
)
Callables and Awaitables
In some cases, you'd want the message returned by your server for some exceptions to call a custom function. This function can either be a synchronous function or an awaitable one. It should expect a single argument, which is the exception being raised:
# Can be a synchronous function as well:
async def write_message(exc: Exception):
return "Whoops"
await catcher.add_scenarios(
catch(MyCustomException2).with_status_code(401).and_call(write_message),
catch(MyCustomException2).with_status_code(403).and_call(lambda exc: str(exc))
)
Handle Several Exceptions Similarly
You can handle several exceptions in the same manner by adding them to the same scenario:
await catcher.add_scenario(
catch(
MyCustomException1,
MyCustomException2,
MyCustomException3
).with_status_code(418).and_return("User-friendly error message")
)
Scenarios as Dictionaries
You can register your scenarios as dictionaries as well:
await catcher.add_scenarios(
{
"exceptions": [ZeroDivisionError],
"constant": "Zero division makes zero sense",
"status_code": 400,
},
{
"exceptions": [EntityNotFound],
"stringify_exception": True,
"status_code": 404,
},
{
"exceptions": [IndexError],
"func": lambda exc: f"Out of bound: {str(exc)}",
"status_code": 418,
},
)
Development
Contributions are warmly welcomed. Before submitting your PR, please run the tests using the following Make target:
make ci
Alternatively, you can run each test suite separately:
-
Unit tests:
make test/py -
Linting with pylint:
make pylint -
Static security checks with bandit:
make pybandit
Metadata
Release files for aiohttp-catcher 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| aiohttp-catcher-0.1.0.tar.gz | 4.9 kB | Without provenance | Details for aiohttp-catcher-0.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| aiohttp_catcher-0.1.0-py3-none-any.whl | Python 3 | none | any | Details for aiohttp_catcher-0.1.0-py3-none-any.whl |
Total release size: 9.6 kB
Release files / aiohttp-catcher-0.1.0.tar.gz
| Download URL | aiohttp-catcher-0.1.0.tar.gz |
|---|---|
| Size | 4.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
107dc696942dcbbdce9f1619ee5b8c922896113cf162c4d630ee9fa7485380e9
|
|
BLAKE2b-256 checksum How to use checksums |
59718b3c43e3ea17985252638a0ba39fc291dc3fe2ee1642d5c08229fa0d15c0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/1.0.0 CPython/3.8.12 Linux/5.11.0-1022-azure
|
Release files / aiohttp_catcher-0.1.0-py3-none-any.whl
| Download URL | aiohttp_catcher-0.1.0-py3-none-any.whl |
|---|---|
| Size | 4.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
317ea467924709e5226bd5627a2e27e5643a76db90f81bd6106d28870b86d078
|
|
BLAKE2b-256 checksum How to use checksums |
de502b08f2a50801b6dcfdd224645bf643d92d260a50fe5bc7330ab727f6aa7c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/1.0.0 CPython/3.8.12 Linux/5.11.0-1022-azure
|
Security for aiohttp-catcher 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.