def initialize(self, routing: routing_reliability.RoutingAndReliability) -> None: """Initialise this request handler with the provided configuration values. :param routing: The routing and reliability component to use to look up values in SDS. """ self.routing = routing read_tracking_id_headers(self.request.headers)
def test_read_invalid_correlation_id(self): headers = HTTPHeaders() headers.add(CORRELATION_ID_HEADER, 'invalid_header_value') with self.assertRaises(tornado.web.HTTPError) as context: read_tracking_id_headers(headers) raised_exception = context.exception self.assertEqual(raised_exception.status_code, 400) self.assertEqual( raised_exception.log_message, "Invalid X-Correlation-ID header. Should be an UUIDv4 matching regex \'^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$\'" )
def test_read_valid_correlation_id(self): with self.subTest("Lower case UUID"): headers = HTTPHeaders() headers.add(CORRELATION_ID_HEADER, FIXED_UUID_LOWER_CASE) read_tracking_id_headers(headers) self.assertEqual(mdc.correlation_id.get(), FIXED_UUID_LOWER_CASE) mdc.correlation_id.set('') with self.subTest("Upper case UUID"): headers = HTTPHeaders() headers.add(CORRELATION_ID_HEADER, FIXED_UUID_UPPER_CASE) read_tracking_id_headers(headers) self.assertEqual(mdc.correlation_id.get(), FIXED_UUID_UPPER_CASE)
async def get(self): read_tracking_id_headers(self.request.headers) self._validate_query_params() org_code = self.get_required_query_param(ORG_CODE_QUERY_PARAMETER_NAME, ORG_CODE_FHIR_IDENTIFIER) service_id = self.get_required_query_param( IDENTIFIER_QUERY_PARAMETER_NAME, SERVICE_ID_FHIR_IDENTIFIER) managing_organization = self.get_optional_query_param( MANAGING_ORGANIZATION_QUERY_PARAMETER_NAME, MANAGING_ORGANIZATION_FHIR_IDENTIFIER) party_key = self.get_optional_query_param( IDENTIFIER_QUERY_PARAMETER_NAME, PARTY_KEY_FHIR_IDENTIFIER) accept_type = get_valid_accept_type(self.request.headers) logger.info( "Looking up accredited system information for {org_code}, {service_id}, {managing_organization}, {party_key}", fparams={ "org_code": org_code, "service_id": service_id, 'managing_organization': managing_organization, 'party_key': party_key }) ldap_result = await self.sds_client.get_as_details( org_code, service_id, managing_organization, party_key) logger.info("Obtained accredited system information. {ldap_result}", fparams={"ldap_result": ldap_result}) base_url = f"{self.request.protocol}://{self.request.host}{self.request.path}/" full_url = unquote(self.request.full_url()) devices = [ build_device_resource(ldap_attributes) for ldap_attributes in ldap_result ] bundle = build_bundle_resource(devices, base_url, full_url) self.write(json.dumps(bundle, indent=2, sort_keys=False)) self.set_header(HttpHeaders.CONTENT_TYPE, accept_type) self.set_header(HttpHeaders.X_CORRELATION_ID, mdc.correlation_id.get())
async def get(self): read_tracking_id_headers(self.request.headers) self._validate_query_params() org_code = self.get_required_query_param(ORG_CODE_QUERY_PARAMETER_NAME, ORG_CODE_FHIR_IDENTIFIER) service_id = self.get_optional_query_param( IDENTIFIER_QUERY_PARAMETER_NAME, SERVICE_ID_FHIR_IDENTIFIER) party_key = self.get_optional_query_param( IDENTIFIER_QUERY_PARAMETER_NAME, PARTY_KEY_FHIR_IDENTIFIER) if not service_id and not party_key: self._raise_invalid_identifier_query_param_error() accept_type = get_valid_accept_type(self.request.headers) logger.info( "Looking up routing and reliability information. {org_code}, {service_id}, {party_key}", fparams={ "org_code": org_code, "service_id": service_id, "party_key": party_key }) ldap_result = await self.sds_client.get_mhs_details( org_code, service_id, party_key) logger.info( "Obtained routing and reliability information. {ldap_result}", fparams={"ldap_result": ldap_result}) base_url = f"{self.request.protocol}://{self.request.host}{self.request.path}/" full_url = unquote(self.request.full_url()) endpoints = [] for ldap_attributes in ldap_result: endpoints += build_endpoint_resources(ldap_attributes) bundle = build_bundle_resource(endpoints, base_url, full_url) self.write(json.dumps(bundle, indent=2, sort_keys=False)) self.set_header(HttpHeaders.CONTENT_TYPE, accept_type) self.set_header(HttpHeaders.X_CORRELATION_ID, mdc.correlation_id.get())
def test_read_missing_correlation_id(self): read_tracking_id_headers(HTTPHeaders()) self.assertRegex(mdc.correlation_id.get(), UUID_PATTERN)
def write_error(self, status_code: int, **kwargs: Any) -> None: read_tracking_id_headers(self.request.headers, raise_error=False) operation_outcome = None additional_headers = [] if status_code == 400: _, exception, _ = kwargs['exc_info'] operation_outcome = OperationOutcome([ Issue(Severity.error, Code.required, [SpineCodings.BAD_REQUEST], diagnostics=str(exception)) ]) elif status_code == 404: operation_outcome = OperationOutcome([ Issue(Severity.error, Code.not_found, [SpineCodings.NO_RECORD_FOUND], diagnostics="HTTP endpoint not found") ]) elif status_code == 405: additional_headers.append(("Allow", "GET")) operation_outcome = OperationOutcome([ Issue(Severity.error, Code.not_supported, [SpineCodings.NOT_IMPLEMENTED], diagnostics="HTTP operation not supported") ]) elif status_code == 406: operation_outcome = OperationOutcome([ Issue(Severity.error, Code.not_supported, [SpineCodings.MISSING_OR_INVALID_HEADER], diagnostics="Accept type not supported") ]) elif status_code == 500: _, exception, _ = kwargs['exc_info'] operation_outcome = OperationOutcome([ Issue(Severity.error, Code.exception, [SpineCodings.INTERNAL_SERVER_ERROR], diagnostics=str(exception)) ]) elif status_code == 502: operation_outcome = OperationOutcome([ Issue(Severity.error, Code.exception, [SpineCodings.INTERNAL_SERVER_ERROR], diagnostics="Invalid LDAP response received") ]) elif status_code == 504: operation_outcome = OperationOutcome([ Issue(Severity.error, Code.timeout, [SpineCodings.INTERNAL_SERVER_ERROR], diagnostics="LDAP request timed out") ]) elif 400 <= status_code <= 499: _, exception, _ = kwargs['exc_info'] operation_outcome = OperationOutcome([ Issue(Severity.error, Code.exception, [SpineCodings.BAD_REQUEST], diagnostics=str(exception)) ]) elif 500 <= status_code < 599: _, exception, _ = kwargs['exc_info'] operation_outcome = OperationOutcome([ Issue(Severity.error, Code.exception, [SpineCodings.INTERNAL_SERVER_ERROR], diagnostics=str(exception)) ]) self.set_header(HttpHeaders.X_CORRELATION_ID, mdc.correlation_id.get()) if operation_outcome is not None: operation_outcome.id = str(mdc.correlation_id.get()) content_type = content_type_validator.APPLICATION_FHIR_JSON serialized = operation_outcome.to_json() self.set_header(HttpHeaders.CONTENT_TYPE, content_type) [self.set_header(kv[0], kv[1]) for kv in additional_headers] self.write(serialized) else: super().write_error(status_code, **kwargs)