blob: d1fc58c2a4bd0894d20f954be4fbe96f24669e06 [file]
import json
from aiohttp import web
from json import JSONDecodeError
from aiohttp.web_exceptions import HTTPUnprocessableEntity
from marshmallow.exceptions import ValidationError
from app.api.v2 import errors
from app.api.v2.schemas.error_schemas import JsonHttpErrorSchema
class JsonHttpErrorResponse:
"""Base class for json formatted versions of aiohttp responses."""
def __init__(self, error, details=None, **kwargs):
kwargs['content_type'] = 'application/json'
kwargs['text'] = JsonHttpErrorSchema.serialize(error, details)
super().__init__(**kwargs)
class JsonHttpBadRequest(JsonHttpErrorResponse, web.HTTPBadRequest):
"""An HTTP 400 response with a json formatted body."""
class JsonHttpForbidden(JsonHttpErrorResponse, web.HTTPForbidden):
"""An HTTP 403 response with a json formatted body."""
pass
class JsonHttpNotFound(JsonHttpErrorResponse, web.HTTPNotFound):
"""An HTTP 404 response with a json formatted body."""
@web.middleware
async def apispec_request_validation_middleware(request, handler):
"""Middleware to handle errors thrown by schema validation
Must be added before `validation_middleware`"""
try:
return await handler(request)
except TypeError as ex:
# ex: Schema `post_load()` instantiates an object, but required
# argument is missing
raise JsonHttpBadRequest(
error='Error parsing JSON',
details=str(ex)
)
except AttributeError as ex:
# ex: JSON contains attribute that does not exist in Schema
# Or any other AttributeError...
raise JsonHttpBadRequest(
error='AttributeError',
details=str(ex)
)
except ValidationError as ex:
# ex: List of objects sent when single object expected
formatted_message = json.dumps({"json": ex.messages}, indent=2)
raise HTTPUnprocessableEntity(
text=formatted_message
)
except JSONDecodeError as ex:
raise JsonHttpBadRequest(
error='Unexpected error occurred while parsing json',
details=str(ex)
)
@web.middleware
async def json_request_validation_middleware(request, handler):
"""Middleware that converts json decoding and marshmallow validation
errors into 400 responses w/ json bodies.
"""
try:
return await handler(request)
except errors.DataValidationError as ex:
raise JsonHttpBadRequest(
error=str(ex),
details={ex.name: ex.value}
)
except errors.RequestValidationError as ex:
raise JsonHttpBadRequest('Received invalid json', details=ex.errors)
except errors.RequestUnparsableJsonError:
raise JsonHttpBadRequest('Unexpected error occurred while parsing json')