From e6227051908080bea94ff907500f5aecf27c0d44 Mon Sep 17 00:00:00 2001 From: Ferras Hamad Date: Sun, 17 May 2020 15:02:20 -0700 Subject: [PATCH 1/2] exception handling --- metadata_service/api/__init__.py | 2 ++ metadata_service/api/admin.py | 5 +++- metadata_service/api/artifact.py | 31 ++++++++++------------- metadata_service/api/flow.py | 21 ++++++++-------- metadata_service/api/metadata.py | 19 ++++++-------- metadata_service/api/run.py | 24 ++++++++---------- metadata_service/api/step.py | 19 +++++++------- metadata_service/api/task.py | 21 ++++++++-------- metadata_service/api/utils.py | 43 ++++++++++++++++++++++++++++++++ 9 files changed, 110 insertions(+), 75 deletions(-) diff --git a/metadata_service/api/__init__.py b/metadata_service/api/__init__.py index e69de29b..e4c4c545 100644 --- a/metadata_service/api/__init__.py +++ b/metadata_service/api/__init__.py @@ -0,0 +1,2 @@ +METADATA_SERVICE_VERSION = 'v1.0' +METADATA_SERVICE_HEADER = 'METADATA_SERVICE_VERSION' \ No newline at end of file diff --git a/metadata_service/api/admin.py b/metadata_service/api/admin.py index 3250a67f..bfc9ef29 100644 --- a/metadata_service/api/admin.py +++ b/metadata_service/api/admin.py @@ -1,9 +1,11 @@ import boto3 import json import os +from multidict import MultiDict from aiohttp import web from botocore.client import Config from .utils import get_traceback_str +from . import METADATA_SERVICE_VERSION, METADATA_SERVICE_HEADER class AuthApi(object): @@ -25,7 +27,8 @@ async def ping(self, request): "405": description: invalid HTTP Method """ - return web.Response(text="pong") + return web.Response(text="pong", headers=MultiDict( + {METADATA_SERVICE_HEADER: METADATA_SERVICE_VERSION})) async def get_authorization_token(self, request): """ diff --git a/metadata_service/api/artifact.py b/metadata_service/api/artifact.py index d8654169..92b5b50b 100644 --- a/metadata_service/api/artifact.py +++ b/metadata_service/api/artifact.py @@ -1,6 +1,6 @@ from aiohttp import web from ..data.postgres_async_db import AsyncPostgresDB -from .utils import read_body +from .utils import read_body, format_response, handle_exceptions import json @@ -39,6 +39,8 @@ def __init__(self, app): ) self._async_table = AsyncPostgresDB.get_instance().artifact_table_postgres + @format_response + @handle_exceptions async def get_artifact(self, request): """ --- @@ -85,14 +87,12 @@ async def get_artifact(self, request): task_id = request.match_info.get("task_id") artifact_name = request.match_info.get("artifact_name") - artifact = await self._async_table.get_artifact( + return await self._async_table.get_artifact( flow_name, run_number, step_name, task_id, artifact_name ) - return web.Response( - status=artifact.response_code, body=json.dumps(artifact.body) - ) - + @format_response + @handle_exceptions async def get_artifacts_by_task(self, request): """ --- @@ -133,13 +133,12 @@ async def get_artifacts_by_task(self, request): step_name = request.match_info.get("step_name") task_id = request.match_info.get("task_id") - artifacts = await self._async_table.get_artifact_in_task( + return await self._async_table.get_artifact_in_task( flow_name, run_number, step_name, task_id ) - return web.Response( - status=artifacts.response_code, body=json.dumps(artifacts.body) - ) + @format_response + @handle_exceptions async def get_artifacts_by_step(self, request): """ --- @@ -174,13 +173,12 @@ async def get_artifacts_by_step(self, request): run_number = request.match_info.get("run_number") step_name = request.match_info.get("step_name") - artifacts = await self._async_table.get_artifact_in_steps( + return await self._async_table.get_artifact_in_steps( flow_name, run_number, step_name ) - return web.Response( - status=artifacts.response_code, body=json.dumps(artifacts.body) - ) + @format_response + @handle_exceptions async def get_artifacts_by_run(self, request): """ --- @@ -209,10 +207,7 @@ async def get_artifacts_by_run(self, request): flow_name = request.match_info.get("flow_id") run_number = request.match_info.get("run_number") - artifacts = await self._async_table.get_artifacts_in_runs(flow_name, run_number) - return web.Response( - status=artifacts.response_code, body=json.dumps(artifacts.body) - ) + return await self._async_table.get_artifacts_in_runs(flow_name, run_number) async def create_artifacts(self, request): """ diff --git a/metadata_service/api/flow.py b/metadata_service/api/flow.py index 869efc1a..435c7a78 100644 --- a/metadata_service/api/flow.py +++ b/metadata_service/api/flow.py @@ -3,7 +3,7 @@ import json from ..data.models import FlowRow from ..data.postgres_async_db import AsyncPostgresDB -from .utils import read_body +from .utils import read_body, format_response, handle_exceptions import asyncio @@ -17,6 +17,8 @@ def __init__(self, app): app.router.add_route("POST", "/flows/{flow_id}", self.create_flow) self._async_table = AsyncPostgresDB.get_instance().flow_table_postgres + @format_response + @handle_exceptions async def create_flow(self, request): """ --- @@ -60,11 +62,10 @@ async def create_flow(self, request): flow = FlowRow( flow_id=flow_name, user_name=user, tags=tags, system_tags=system_tags ) - response = await self._async_table.add_flow(flow) - return web.Response( - status=response.response_code, body=json.dumps(response.body) - ) + return await self._async_table.add_flow(flow) + @format_response + @handle_exceptions async def get_flow(self, request): """ --- @@ -89,11 +90,10 @@ async def get_flow(self, request): """ flow_name = request.match_info.get("flow_id") - flow_response = await self._async_table.get_flow(flow_name) - return web.Response( - status=flow_response.response_code, body=json.dumps(flow_response.body) - ) + return await self._async_table.get_flow(flow_name) + @format_response + @handle_exceptions async def get_all_flows(self, request): """ --- @@ -108,5 +108,4 @@ async def get_all_flows(self, request): "405": description: invalid HTTP Method """ - flows = await self._async_table.get_all_flows() - return web.Response(status=flows.response_code, body=json.dumps(flows.body)) + return await self._async_table.get_all_flows() diff --git a/metadata_service/api/metadata.py b/metadata_service/api/metadata.py index d487c083..a3acbf07 100644 --- a/metadata_service/api/metadata.py +++ b/metadata_service/api/metadata.py @@ -1,10 +1,9 @@ from aiohttp import web import json -from .utils import read_body +from .utils import read_body, format_response, handle_exceptions import asyncio from ..data.postgres_async_db import AsyncPostgresDB - class MetadataApi(object): _metadata_table = None lock = asyncio.Lock() @@ -30,6 +29,9 @@ def __init__(self, app): self._async_table = AsyncPostgresDB.get_instance().metadata_table_postgres + + @format_response + @handle_exceptions async def get_metadata(self, request): """ --- @@ -69,14 +71,12 @@ async def get_metadata(self, request): run_number = request.match_info.get("run_number") step_name = request.match_info.get("step_name") task_id = request.match_info.get("task_id") - metadata_response = await self._async_table.get_metadata( + return await self._async_table.get_metadata( flow_name, run_number, step_name, task_id ) - return web.Response( - status=metadata_response.response_code, - body=json.dumps(metadata_response.body), - ) + @format_response + @handle_exceptions async def get_metadata_by_run(self, request): """ --- @@ -104,12 +104,9 @@ async def get_metadata_by_run(self, request): """ flow_name = request.match_info.get("flow_id") run_number = request.match_info.get("run_number") - metadata_runs = await self._async_table.get_metadata_in_runs( + return await self._async_table.get_metadata_in_runs( flow_name, run_number ) - return web.Response( - status=metadata_runs.response_code, body=json.dumps(metadata_runs.body) - ) async def create_metadata(self, request): """ diff --git a/metadata_service/api/run.py b/metadata_service/api/run.py index 64999ed5..f3efabbf 100644 --- a/metadata_service/api/run.py +++ b/metadata_service/api/run.py @@ -1,7 +1,5 @@ import asyncio -import json -from aiohttp import web -from .utils import read_body +from .utils import read_body, format_response, handle_exceptions from ..data.models import RunRow from ..data.postgres_async_db import AsyncPostgresDB @@ -16,6 +14,8 @@ def __init__(self, app): app.router.add_route("POST", "/flows/{flow_id}/run", self.create_run) self._async_table = AsyncPostgresDB.get_instance().run_table_postgres + @format_response + @handle_exceptions async def get_run(self, request): """ --- @@ -45,11 +45,10 @@ async def get_run(self, request): """ flow_name = request.match_info.get("flow_id") run_number = request.match_info.get("run_number") - run_response = await self._async_table.get_run(flow_name, run_number) - return web.Response( - status=run_response.response_code, body=json.dumps(run_response.body) - ) + return await self._async_table.get_run(flow_name, run_number) + @format_response + @handle_exceptions async def get_all_runs(self, request): """ --- @@ -71,10 +70,10 @@ async def get_all_runs(self, request): description: invalid HTTP Method """ flow_name = request.match_info.get("flow_id") - runs = await self._async_table.get_all_runs(flow_name) - - return web.Response(status=runs.response_code, body=json.dumps(runs.body)) + return await self._async_table.get_all_runs(flow_name) + @format_response + @handle_exceptions async def create_run(self, request): """ --- @@ -118,7 +117,4 @@ async def create_run(self, request): flow_id=flow_name, user_name=user, tags=tags, system_tags=system_tags ) - run_response = await self._async_table.add_run(run_row) - return web.Response( - status=run_response.response_code, body=json.dumps(run_response.body) - ) + return await self._async_table.add_run(run_row) diff --git a/metadata_service/api/step.py b/metadata_service/api/step.py index 1eedce1e..b0ee7229 100644 --- a/metadata_service/api/step.py +++ b/metadata_service/api/step.py @@ -1,7 +1,5 @@ -from aiohttp import web from ..data.models import StepRow -import json -from .utils import read_body +from .utils import read_body, format_response, handle_exceptions from ..data.postgres_async_db import AsyncPostgresDB @@ -23,6 +21,8 @@ def __init__(self, app): ) self._async_table = AsyncPostgresDB.get_instance().step_table_postgres + @format_response + @handle_exceptions async def get_steps(self, request): """ --- @@ -50,9 +50,10 @@ async def get_steps(self, request): """ flow_name = request.match_info.get("flow_id") run_number = request.match_info.get("run_number") - steps = await self._async_table.get_steps(flow_name, run_number) - return web.Response(status=steps.response_code, body=json.dumps(steps.body)) + return await self._async_table.get_steps(flow_name, run_number) + @format_response + @handle_exceptions async def get_step(self, request): """ --- @@ -88,9 +89,10 @@ async def get_step(self, request): flow_name = request.match_info.get("flow_id") run_number = request.match_info.get("run_number") step_name = request.match_info.get("step_name") - step = await self._async_table.get_step(flow_name, run_number, step_name) - return web.Response(status=step.response_code, body=json.dumps(step.body)) + return await self._async_table.get_step(flow_name, run_number, step_name) + @format_response + @handle_exceptions async def create_step(self, request): """ --- @@ -147,5 +149,4 @@ async def create_step(self, request): flow_name, run_number, user, step_name, tags=tags, system_tags=system_tags ) - step = await self._async_table.add_step(step_row) - return web.Response(status=step.response_code, body=json.dumps(step.body)) + return await self._async_table.add_step(step_row) diff --git a/metadata_service/api/task.py b/metadata_service/api/task.py index 96b7ca50..79089b50 100644 --- a/metadata_service/api/task.py +++ b/metadata_service/api/task.py @@ -1,8 +1,6 @@ -from aiohttp import web from ..data.models import TaskRow from ..data.postgres_async_db import AsyncPostgresDB -import json -from .utils import read_body +from .utils import read_body, format_response, handle_exceptions import asyncio @@ -28,6 +26,8 @@ def __init__(self, app): ) self._async_table = AsyncPostgresDB.get_instance().task_table_postgres + @format_response + @handle_exceptions async def get_tasks(self, request): """ --- @@ -62,9 +62,10 @@ async def get_tasks(self, request): run_number = request.match_info.get("run_number") step_name = request.match_info.get("step_name") - tasks = await self._async_table.get_tasks(flow_name, run_number, step_name) - return web.Response(status=tasks.response_code, body=json.dumps(tasks.body)) + return await self._async_table.get_tasks(flow_name, run_number, step_name) + @format_response + @handle_exceptions async def get_task(self, request): """ --- @@ -104,11 +105,12 @@ async def get_task(self, request): run_number = request.match_info.get("run_number") step_name = request.match_info.get("step_name") task_id = request.match_info.get("task_id") - task = await self._async_table.get_task( + return await self._async_table.get_task( flow_name, run_number, step_name, task_id ) - return web.Response(status=task.response_code, body=json.dumps(task.body)) + @format_response + @handle_exceptions async def create_task(self, request): """ --- @@ -168,7 +170,4 @@ async def create_task(self, request): tags=tags, system_tags=system_tags, ) - task_response = await self._async_table.add_task(task) - return web.Response( - status=task_response.response_code, body=json.dumps(task_response.body) - ) + return await self._async_table.add_task(task) diff --git a/metadata_service/api/utils.py b/metadata_service/api/utils.py index 1bec40ac..11fb427e 100644 --- a/metadata_service/api/utils.py +++ b/metadata_service/api/utils.py @@ -1,6 +1,10 @@ import json import sys import traceback +from multidict import MultiDict +from aiohttp import web +from functools import wraps +from . import METADATA_SERVICE_VERSION, METADATA_SERVICE_HEADER async def read_body(request_content): @@ -27,3 +31,42 @@ def get_traceback_str(): "".join(exc_line), ] ) + + +def http_500(msg): + body = { + 'traceback': get_traceback_str(), + 'detail': msg, + 'status': 500, + 'title': 'Internal Server Error', + 'type': 'about:blank' + } + + return 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 Exception as err: + return http_500(str(err)) + + return wrapper + + +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 From e337bd5a71a9db97d62e5a930fedf09b5a91a010 Mon Sep 17 00:00:00 2001 From: Ferras Hamad Date: Sun, 17 May 2020 15:02:20 -0700 Subject: [PATCH 2/2] exception handling --- metadata_service/api/__init__.py | 2 ++ metadata_service/api/admin.py | 5 +++- metadata_service/api/artifact.py | 14 +++++------ metadata_service/api/flow.py | 21 ++++++++-------- metadata_service/api/metadata.py | 19 ++++++-------- metadata_service/api/run.py | 24 ++++++++---------- metadata_service/api/step.py | 19 +++++++------- metadata_service/api/task.py | 21 ++++++++-------- metadata_service/api/utils.py | 43 ++++++++++++++++++++++++++++++++ 9 files changed, 104 insertions(+), 64 deletions(-) diff --git a/metadata_service/api/__init__.py b/metadata_service/api/__init__.py index e69de29b..e4c4c545 100644 --- a/metadata_service/api/__init__.py +++ b/metadata_service/api/__init__.py @@ -0,0 +1,2 @@ +METADATA_SERVICE_VERSION = 'v1.0' +METADATA_SERVICE_HEADER = 'METADATA_SERVICE_VERSION' \ No newline at end of file diff --git a/metadata_service/api/admin.py b/metadata_service/api/admin.py index 3250a67f..bfc9ef29 100644 --- a/metadata_service/api/admin.py +++ b/metadata_service/api/admin.py @@ -1,9 +1,11 @@ import boto3 import json import os +from multidict import MultiDict from aiohttp import web from botocore.client import Config from .utils import get_traceback_str +from . import METADATA_SERVICE_VERSION, METADATA_SERVICE_HEADER class AuthApi(object): @@ -25,7 +27,8 @@ async def ping(self, request): "405": description: invalid HTTP Method """ - return web.Response(text="pong") + return web.Response(text="pong", headers=MultiDict( + {METADATA_SERVICE_HEADER: METADATA_SERVICE_VERSION})) async def get_authorization_token(self, request): """ diff --git a/metadata_service/api/artifact.py b/metadata_service/api/artifact.py index 911226c9..4788cc03 100644 --- a/metadata_service/api/artifact.py +++ b/metadata_service/api/artifact.py @@ -1,6 +1,6 @@ from aiohttp import web from ..data.postgres_async_db import AsyncPostgresDB -from .utils import read_body +from .utils import read_body, format_response, handle_exceptions import json @@ -39,6 +39,8 @@ def __init__(self, app): ) self._async_table = AsyncPostgresDB.get_instance().artifact_table_postgres + @format_response + @handle_exceptions async def get_artifact(self, request): """ --- @@ -85,12 +87,9 @@ async def get_artifact(self, request): task_id = request.match_info.get("task_id") artifact_name = request.match_info.get("artifact_name") - artifact = await self._async_table.get_artifact( + return await self._async_table.get_artifact( flow_name, run_number, step_name, task_id, artifact_name ) - return web.Response( - status=artifact.response_code, body=json.dumps(artifact.body) - ) async def get_artifacts_by_task(self, request): """ @@ -136,7 +135,7 @@ async def get_artifacts_by_task(self, request): flow_name, run_number, step_name, task_id ) filtered_body = ArtificatsApi._filter_artifacts_by_attempt_id( - artifacts) + artifacts.body) return web.Response( status=artifacts.response_code, body=json.dumps(filtered_body) ) @@ -178,6 +177,7 @@ async def get_artifacts_by_step(self, request): artifacts = await self._async_table.get_artifact_in_steps( flow_name, run_number, step_name ) + filtered_body = ArtificatsApi._filter_artifacts_by_attempt_id(artifacts.body) return web.Response( status=artifacts.response_code, body=json.dumps(filtered_body) @@ -212,7 +212,7 @@ async def get_artifacts_by_run(self, request): run_number = request.match_info.get("run_number") artifacts = await self._async_table.get_artifacts_in_runs(flow_name, run_number) - filtered_body = ArtificatsApi._filter_artifacts_by_attempt_id(artifacts) + filtered_body = ArtificatsApi._filter_artifacts_by_attempt_id(artifacts.body) return web.Response( status=artifacts.response_code, body=json.dumps(filtered_body) ) diff --git a/metadata_service/api/flow.py b/metadata_service/api/flow.py index 869efc1a..435c7a78 100644 --- a/metadata_service/api/flow.py +++ b/metadata_service/api/flow.py @@ -3,7 +3,7 @@ import json from ..data.models import FlowRow from ..data.postgres_async_db import AsyncPostgresDB -from .utils import read_body +from .utils import read_body, format_response, handle_exceptions import asyncio @@ -17,6 +17,8 @@ def __init__(self, app): app.router.add_route("POST", "/flows/{flow_id}", self.create_flow) self._async_table = AsyncPostgresDB.get_instance().flow_table_postgres + @format_response + @handle_exceptions async def create_flow(self, request): """ --- @@ -60,11 +62,10 @@ async def create_flow(self, request): flow = FlowRow( flow_id=flow_name, user_name=user, tags=tags, system_tags=system_tags ) - response = await self._async_table.add_flow(flow) - return web.Response( - status=response.response_code, body=json.dumps(response.body) - ) + return await self._async_table.add_flow(flow) + @format_response + @handle_exceptions async def get_flow(self, request): """ --- @@ -89,11 +90,10 @@ async def get_flow(self, request): """ flow_name = request.match_info.get("flow_id") - flow_response = await self._async_table.get_flow(flow_name) - return web.Response( - status=flow_response.response_code, body=json.dumps(flow_response.body) - ) + return await self._async_table.get_flow(flow_name) + @format_response + @handle_exceptions async def get_all_flows(self, request): """ --- @@ -108,5 +108,4 @@ async def get_all_flows(self, request): "405": description: invalid HTTP Method """ - flows = await self._async_table.get_all_flows() - return web.Response(status=flows.response_code, body=json.dumps(flows.body)) + return await self._async_table.get_all_flows() diff --git a/metadata_service/api/metadata.py b/metadata_service/api/metadata.py index d487c083..a3acbf07 100644 --- a/metadata_service/api/metadata.py +++ b/metadata_service/api/metadata.py @@ -1,10 +1,9 @@ from aiohttp import web import json -from .utils import read_body +from .utils import read_body, format_response, handle_exceptions import asyncio from ..data.postgres_async_db import AsyncPostgresDB - class MetadataApi(object): _metadata_table = None lock = asyncio.Lock() @@ -30,6 +29,9 @@ def __init__(self, app): self._async_table = AsyncPostgresDB.get_instance().metadata_table_postgres + + @format_response + @handle_exceptions async def get_metadata(self, request): """ --- @@ -69,14 +71,12 @@ async def get_metadata(self, request): run_number = request.match_info.get("run_number") step_name = request.match_info.get("step_name") task_id = request.match_info.get("task_id") - metadata_response = await self._async_table.get_metadata( + return await self._async_table.get_metadata( flow_name, run_number, step_name, task_id ) - return web.Response( - status=metadata_response.response_code, - body=json.dumps(metadata_response.body), - ) + @format_response + @handle_exceptions async def get_metadata_by_run(self, request): """ --- @@ -104,12 +104,9 @@ async def get_metadata_by_run(self, request): """ flow_name = request.match_info.get("flow_id") run_number = request.match_info.get("run_number") - metadata_runs = await self._async_table.get_metadata_in_runs( + return await self._async_table.get_metadata_in_runs( flow_name, run_number ) - return web.Response( - status=metadata_runs.response_code, body=json.dumps(metadata_runs.body) - ) async def create_metadata(self, request): """ diff --git a/metadata_service/api/run.py b/metadata_service/api/run.py index 64999ed5..f3efabbf 100644 --- a/metadata_service/api/run.py +++ b/metadata_service/api/run.py @@ -1,7 +1,5 @@ import asyncio -import json -from aiohttp import web -from .utils import read_body +from .utils import read_body, format_response, handle_exceptions from ..data.models import RunRow from ..data.postgres_async_db import AsyncPostgresDB @@ -16,6 +14,8 @@ def __init__(self, app): app.router.add_route("POST", "/flows/{flow_id}/run", self.create_run) self._async_table = AsyncPostgresDB.get_instance().run_table_postgres + @format_response + @handle_exceptions async def get_run(self, request): """ --- @@ -45,11 +45,10 @@ async def get_run(self, request): """ flow_name = request.match_info.get("flow_id") run_number = request.match_info.get("run_number") - run_response = await self._async_table.get_run(flow_name, run_number) - return web.Response( - status=run_response.response_code, body=json.dumps(run_response.body) - ) + return await self._async_table.get_run(flow_name, run_number) + @format_response + @handle_exceptions async def get_all_runs(self, request): """ --- @@ -71,10 +70,10 @@ async def get_all_runs(self, request): description: invalid HTTP Method """ flow_name = request.match_info.get("flow_id") - runs = await self._async_table.get_all_runs(flow_name) - - return web.Response(status=runs.response_code, body=json.dumps(runs.body)) + return await self._async_table.get_all_runs(flow_name) + @format_response + @handle_exceptions async def create_run(self, request): """ --- @@ -118,7 +117,4 @@ async def create_run(self, request): flow_id=flow_name, user_name=user, tags=tags, system_tags=system_tags ) - run_response = await self._async_table.add_run(run_row) - return web.Response( - status=run_response.response_code, body=json.dumps(run_response.body) - ) + return await self._async_table.add_run(run_row) diff --git a/metadata_service/api/step.py b/metadata_service/api/step.py index 1eedce1e..b0ee7229 100644 --- a/metadata_service/api/step.py +++ b/metadata_service/api/step.py @@ -1,7 +1,5 @@ -from aiohttp import web from ..data.models import StepRow -import json -from .utils import read_body +from .utils import read_body, format_response, handle_exceptions from ..data.postgres_async_db import AsyncPostgresDB @@ -23,6 +21,8 @@ def __init__(self, app): ) self._async_table = AsyncPostgresDB.get_instance().step_table_postgres + @format_response + @handle_exceptions async def get_steps(self, request): """ --- @@ -50,9 +50,10 @@ async def get_steps(self, request): """ flow_name = request.match_info.get("flow_id") run_number = request.match_info.get("run_number") - steps = await self._async_table.get_steps(flow_name, run_number) - return web.Response(status=steps.response_code, body=json.dumps(steps.body)) + return await self._async_table.get_steps(flow_name, run_number) + @format_response + @handle_exceptions async def get_step(self, request): """ --- @@ -88,9 +89,10 @@ async def get_step(self, request): flow_name = request.match_info.get("flow_id") run_number = request.match_info.get("run_number") step_name = request.match_info.get("step_name") - step = await self._async_table.get_step(flow_name, run_number, step_name) - return web.Response(status=step.response_code, body=json.dumps(step.body)) + return await self._async_table.get_step(flow_name, run_number, step_name) + @format_response + @handle_exceptions async def create_step(self, request): """ --- @@ -147,5 +149,4 @@ async def create_step(self, request): flow_name, run_number, user, step_name, tags=tags, system_tags=system_tags ) - step = await self._async_table.add_step(step_row) - return web.Response(status=step.response_code, body=json.dumps(step.body)) + return await self._async_table.add_step(step_row) diff --git a/metadata_service/api/task.py b/metadata_service/api/task.py index 96b7ca50..79089b50 100644 --- a/metadata_service/api/task.py +++ b/metadata_service/api/task.py @@ -1,8 +1,6 @@ -from aiohttp import web from ..data.models import TaskRow from ..data.postgres_async_db import AsyncPostgresDB -import json -from .utils import read_body +from .utils import read_body, format_response, handle_exceptions import asyncio @@ -28,6 +26,8 @@ def __init__(self, app): ) self._async_table = AsyncPostgresDB.get_instance().task_table_postgres + @format_response + @handle_exceptions async def get_tasks(self, request): """ --- @@ -62,9 +62,10 @@ async def get_tasks(self, request): run_number = request.match_info.get("run_number") step_name = request.match_info.get("step_name") - tasks = await self._async_table.get_tasks(flow_name, run_number, step_name) - return web.Response(status=tasks.response_code, body=json.dumps(tasks.body)) + return await self._async_table.get_tasks(flow_name, run_number, step_name) + @format_response + @handle_exceptions async def get_task(self, request): """ --- @@ -104,11 +105,12 @@ async def get_task(self, request): run_number = request.match_info.get("run_number") step_name = request.match_info.get("step_name") task_id = request.match_info.get("task_id") - task = await self._async_table.get_task( + return await self._async_table.get_task( flow_name, run_number, step_name, task_id ) - return web.Response(status=task.response_code, body=json.dumps(task.body)) + @format_response + @handle_exceptions async def create_task(self, request): """ --- @@ -168,7 +170,4 @@ async def create_task(self, request): tags=tags, system_tags=system_tags, ) - task_response = await self._async_table.add_task(task) - return web.Response( - status=task_response.response_code, body=json.dumps(task_response.body) - ) + return await self._async_table.add_task(task) diff --git a/metadata_service/api/utils.py b/metadata_service/api/utils.py index 1bec40ac..11fb427e 100644 --- a/metadata_service/api/utils.py +++ b/metadata_service/api/utils.py @@ -1,6 +1,10 @@ import json import sys import traceback +from multidict import MultiDict +from aiohttp import web +from functools import wraps +from . import METADATA_SERVICE_VERSION, METADATA_SERVICE_HEADER async def read_body(request_content): @@ -27,3 +31,42 @@ def get_traceback_str(): "".join(exc_line), ] ) + + +def http_500(msg): + body = { + 'traceback': get_traceback_str(), + 'detail': msg, + 'status': 500, + 'title': 'Internal Server Error', + 'type': 'about:blank' + } + + return 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 Exception as err: + return http_500(str(err)) + + return wrapper + + +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