services/metadata_service/api/utils.py (47 lines of code) (raw):
import json
from functools import wraps
import collections
from aiohttp import web
from multidict import MultiDict
from importlib import metadata
from services.utils import get_traceback_str
version = metadata.version("metadata_service")
METADATA_SERVICE_VERSION = version
METADATA_SERVICE_HEADER = 'METADATA_SERVICE_VERSION'
ServiceResponse = collections.namedtuple("ServiceResponse", "response_code body")
def format_response(func):
"""handle formatting"""
@wraps(func)
async def wrapper(*args, **kwargs):
db_response = await func(*args, **kwargs)
return web.Response(status=db_response.response_code,
body=json.dumps(db_response.body),
headers=MultiDict(
{METADATA_SERVICE_HEADER: METADATA_SERVICE_VERSION}))
return wrapper
def web_response(status: int, body):
return web.Response(status=status,
body=json.dumps(body),
headers=MultiDict(
{"Content-Type": "application/json",
METADATA_SERVICE_HEADER: METADATA_SERVICE_VERSION}))
def http_500(msg, traceback_str=None):
# NOTE: worth considering if we want to expose tracebacks in the future in the api messages.
if traceback_str is None:
traceback_str = get_traceback_str()
body = {
'traceback': traceback_str,
'detail': msg,
'status': 500,
'title': 'Internal Server Error',
'type': 'about:blank'
}
return ServiceResponse(500, body)
def handle_exceptions(func):
"""Catch exceptions and return appropriate HTTP error."""
@wraps(func)
async def wrapper(*args, **kwargs):
try:
return await func(*args, **kwargs)
except web.HTTPClientError as ex:
return ServiceResponse(ex.status_code, ex.reason)
except Exception as err:
return http_500(str(err))
return wrapper