Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file.
27 changes: 27 additions & 0 deletions backend/src/controller/aws_apig_event_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
"""Utility module for interacting with the AWS API Gateway event provided to controllers"""
from typing import Optional

from aws_lambda_typing.events import APIGatewayProxyEventV1

from controller.constants import SUPPLIER_SYSTEM_HEADER_NAME
from models.errors import UnauthorizedError
from utils import dict_utils


def get_path_parameter(event: APIGatewayProxyEventV1, param_name: str) -> str:
return dict_utils.get_field(
event["pathParameters"],
param_name,
default=""
)


def get_supplier_system_header(event: APIGatewayProxyEventV1) -> str:
"""Retrieves the supplier system header from the API Gateway event"""
supplier_system: Optional[str] = dict_utils.get_field(dict(event), "headers", SUPPLIER_SYSTEM_HEADER_NAME)

if supplier_system is None:
# SupplierSystem header must be provided for looking up permissions
raise UnauthorizedError()

return supplier_system
24 changes: 24 additions & 0 deletions backend/src/controller/aws_apig_response_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
"""Utility module providing helper functions for dealing with response formats for AWS API Gateway"""
import json
from typing import Optional


def create_response(
status_code: int,
body: Optional[dict | str] = None,
headers: Optional[dict] = None
):
"""Creates response body as per Lambda -> API Gateway proxy integration"""
if body is not None:
if isinstance(body, dict):
body = json.dumps(body)
if headers:
headers["Content-Type"] = "application/fhir+json"
else:
headers = {"Content-Type": "application/fhir+json"}

return {
"statusCode": status_code,
"headers": headers if headers else {},
**({"body": body} if body else {}),
}
5 changes: 5 additions & 0 deletions backend/src/controller/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
"""FHIR Controller constants"""


SUPPLIER_SYSTEM_HEADER_NAME = "SupplierSystem"
E_TAG_HEADER_NAME = "E-Tag"
42 changes: 42 additions & 0 deletions backend/src/controller/fhir_api_exception_handler.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
"""Module for the global FHIR API exception handler"""
import functools
import uuid
from typing import Callable, Type

from clients import logger
from constants import GENERIC_SERVER_ERROR_DIAGNOSTICS_MESSAGE
from controller.aws_apig_response_utils import create_response
from models.errors import UnauthorizedVaxError, UnauthorizedError, ResourceNotFoundError, create_operation_outcome, \
Severity, Code


_CUSTOM_EXCEPTION_TO_STATUS_MAP: dict[Type[Exception], int] = {
UnauthorizedError: 403,
UnauthorizedVaxError: 403,
ResourceNotFoundError: 404
}


def fhir_api_exception_handler(function: Callable) -> Callable:
"""Decorator to handle any expected FHIR API exceptions or unexpected exception and provide a valid response to
the client"""

@functools.wraps(function)
def wrapper(*args, **kwargs):
try:
return function(*args, **kwargs)
except tuple(_CUSTOM_EXCEPTION_TO_STATUS_MAP) as exc:
status_code = _CUSTOM_EXCEPTION_TO_STATUS_MAP[type(exc)]
return create_response(status_code=status_code, body=exc.to_operation_outcome())
except Exception: # pylint: disable = broad-exception-caught
logger.exception("Unhandled exception")
server_error = create_operation_outcome(
resource_id=str(uuid.uuid4()),
severity=Severity.error,
code=Code.server_error,
diagnostics=GENERIC_SERVER_ERROR_DIAGNOSTICS_MESSAGE,
)
return create_response(500, server_error)

return wrapper

Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Function to send the request directly to lambda (or return appropriate diagnostics if this is not possible)"""

from fhir_batch_service import ImmunizationBatchService
from fhir_batch_repository import ImmunizationBatchRepository
from service.fhir_batch_service import ImmunizationBatchService
from repository.fhir_batch_repository import ImmunizationBatchRepository


def make_batch_controller():
Expand Down
Loading
Loading