diff --git a/blurb_it/middleware.py b/blurb_it/middleware.py index e79d543..e04dea2 100644 --- a/blurb_it/middleware.py +++ b/blurb_it/middleware.py @@ -4,16 +4,24 @@ @web.middleware async def error_middleware(request, handler): - """Middleware to render error message using the template renderer.""" + """Middleware to render error message using the template renderer. + + Only client and server errors are rendered. Redirects and other + non-error responses raised as exceptions pass through untouched. + The rendered page keeps the original status code, so monitoring, + health probes and Sentry see the real error instead of a 200. + """ try: response = await handler(request) except web.HTTPException as ex: + if ex.status < 400: + raise if ex.text: message = ex.text else: message = ex.reason context = {"error_message": message, "status": ex.status} response = aiohttp_jinja2.render_template( - "error.html", request, context=context + "error.html", request, context=context, status=ex.status ) return response diff --git a/tests/test_middleware.py b/tests/test_middleware.py new file mode 100644 index 0000000..20e16cf --- /dev/null +++ b/tests/test_middleware.py @@ -0,0 +1,59 @@ +from __future__ import annotations + +import pathlib + +import aiohttp_jinja2 +import jinja2 +from aiohttp import web + +from blurb_it import middleware + + +def create_app() -> web.Application: + app = web.Application(middlewares=[middleware.error_middleware]) + aiohttp_jinja2.setup( + app, loader=jinja2.FileSystemLoader(pathlib.Path.cwd() / "templates") + ) + return app + + +async def test_not_found_keeps_status_code(aiohttp_client) -> None: + app = create_app() + client = await aiohttp_client(app) + + response = await client.get("/does-not-exist") + + assert response.status == 404 + text = await response.text() + assert "