From 4c5e0c3e726c3a1f8e1941dbdc67c7d9921df297 Mon Sep 17 00:00:00 2001 From: adamclarkson Date: Fri, 10 Oct 2025 11:32:55 +0100 Subject: [PATCH 1/9] NPA-5534: OAS update for GET Questionnaire Response --- .../validated-relationships-service-api.yaml | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/specification/validated-relationships-service-api.yaml b/specification/validated-relationships-service-api.yaml index b430f911..8ca87013 100644 --- a/specification/validated-relationships-service-api.yaml +++ b/specification/validated-relationships-service-api.yaml @@ -3,7 +3,7 @@ openapi: "3.0.0" info: title: "Validated Relationships Service API" - version: "1.13.0" + version: "1.14.0" description: | ## Overview Use this API to access the Validated Relationships Service - the national electronic database of relationships @@ -300,6 +300,8 @@ paths: examples: internalServerError: $ref: "./examples/responses/errors/internal-server-error.yaml#/InternalServerError" + + /QuestionnaireResponse/{id}: get: summary: Get a proxy access request description: | @@ -308,7 +310,7 @@ paths: QuestionnaireResponse document that was previously submitted. ## Request Requirements - A valid access request ID must be provided as a query parameter. This access request ID is returned + A valid access request ID must be provided as a path parameter. This access request ID is returned when a QuestionnaireResponse is initially submitted via the POST endpoint. ## Access modes @@ -319,12 +321,12 @@ paths: ## Sandbox test scenarios - | Scenario | Request | Response | - | -------------------------------- | -----------------------------------------| ------------------------------------------------------------- | - | Valid access request ID | `ID=156e1560-e532-4e2a-85ad-5aeff03dc43e`| HTTP Status 200 with QuestionnaireResponse | - | Invalid access request ID | `ID=INVALID` | HTTP Status 400 with INVALID_IDENTIFIER_VALUE message | - | Missing access request ID | No ID parameter | HTTP Status 400 with BAD_REQUEST message | - | Non-existent access request ID | `ID=60d09b82-f4bb-41f9-b41e-767999b4ac9b`| HTTP Status 404 with QUESTIONNAIRE_RESPONSE_NOT_FOUND message | + | Scenario | Request | Response | + | -------------------------------- | ------------------------------------------------ | ------------------------------------------------------------- | + | Valid access request ID | ID value: `156e1560-e532-4e2a-85ad-5aeff03dc43e` | HTTP Status 200 with QuestionnaireResponse | + | Invalid access request ID | ID value: `INVALID` | HTTP Status 400 with INVALID_IDENTIFIER_VALUE message | + | Missing access request ID | No ID path parameter | HTTP Status 400 with BAD_REQUEST message | + | Non-existent access request ID | ID value: `60d09b82-f4bb-41f9-b41e-767999b4ac9b` | HTTP Status 404 with QUESTIONNAIRE_RESPONSE_NOT_FOUND message | operationId: get-questionnaire-response parameters: From da60ccde448b39866cb225cea67ec2530c5dc40d Mon Sep 17 00:00:00 2001 From: adamclarkson Date: Fri, 10 Oct 2025 15:14:11 +0100 Subject: [PATCH 2/9] NPA-5534: Updated params in OAS --- specification/validated-relationships-service-api.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/specification/validated-relationships-service-api.yaml b/specification/validated-relationships-service-api.yaml index 8ca87013..c0b9d2b4 100644 --- a/specification/validated-relationships-service-api.yaml +++ b/specification/validated-relationships-service-api.yaml @@ -333,8 +333,8 @@ paths: - $ref: "#/components/parameters/BearerAuthorization" - $ref: "#/components/parameters/RequestID" - $ref: "#/components/parameters/CorrelationID" - - name: ID - in: query + - name: id + in: path description: The unique access request ID of the QuestionnaireResponse to retrieve required: true schema: From 8ffeefef6ca0d35d96f1abe48977a886a44d12fc Mon Sep 17 00:00:00 2001 From: adamclarkson Date: Tue, 14 Oct 2025 13:05:52 +0100 Subject: [PATCH 3/9] NPA-5534: Updated param in OAS --- .../responses/errors/method_not_allowed.yaml | 15 ++++++++++++ .../validated-relationships-service-api.yaml | 23 +++++++++++-------- 2 files changed, 29 insertions(+), 9 deletions(-) create mode 100644 specification/examples/responses/errors/method_not_allowed.yaml diff --git a/specification/examples/responses/errors/method_not_allowed.yaml b/specification/examples/responses/errors/method_not_allowed.yaml new file mode 100644 index 00000000..37c27618 --- /dev/null +++ b/specification/examples/responses/errors/method_not_allowed.yaml @@ -0,0 +1,15 @@ +MethodNotAllowedError: + summary: Method is not allowed + description: 405 error response bundle as HTTP method is not allowed + value: + resourceType: "OperationOutcome" + issue: + - code: "not-supported" + details: + coding: + - system: "https://fhir.nhs.uk/R4/CodeSystem/ValidatedRelationships-ErrorOrWarningCode" + version: "1" + code: "METHOD_NOT_ALLOWED" + display: "The method is not allowed." + diagnostics: "The method is not allowed for the requested resource." + severity: "error" diff --git a/specification/validated-relationships-service-api.yaml b/specification/validated-relationships-service-api.yaml index c0b9d2b4..83da8353 100644 --- a/specification/validated-relationships-service-api.yaml +++ b/specification/validated-relationships-service-api.yaml @@ -325,7 +325,7 @@ paths: | -------------------------------- | ------------------------------------------------ | ------------------------------------------------------------- | | Valid access request ID | ID value: `156e1560-e532-4e2a-85ad-5aeff03dc43e` | HTTP Status 200 with QuestionnaireResponse | | Invalid access request ID | ID value: `INVALID` | HTTP Status 400 with INVALID_IDENTIFIER_VALUE message | - | Missing access request ID | No ID path parameter | HTTP Status 400 with BAD_REQUEST message | + | Missing access request ID | No ID path parameter | HTTP Status 405 with METHOD_NOT_ALLOWED message | | Non-existent access request ID | ID value: `60d09b82-f4bb-41f9-b41e-767999b4ac9b` | HTTP Status 404 with QUESTIONNAIRE_RESPONSE_NOT_FOUND message | operationId: get-questionnaire-response @@ -333,13 +333,7 @@ paths: - $ref: "#/components/parameters/BearerAuthorization" - $ref: "#/components/parameters/RequestID" - $ref: "#/components/parameters/CorrelationID" - - name: id - in: path - description: The unique access request ID of the QuestionnaireResponse to retrieve - required: true - schema: - type: string - example: "156e1560-e532-4e2a-85ad-5aeff03dc43e" + - $ref: "#/components/parameters/AccessRequestID" responses: "200": description: QuestionnaireResponse successfully retrieved. @@ -376,7 +370,7 @@ paths: invalidAccessRequestID: $ref: "./examples/responses/GET_QuestionnaireResponse/errors/invalid_access_request_id.yaml#/InvalidAccessRequestID" missingAccessRequestID: - $ref: "./examples/responses/GET_QuestionnaireResponse/errors/missing_access_request_id.yaml#/MissingAccessRequestID" + $ref: "./examples/responses/errors/method_not_allowed.yaml#/MethodNotAllowedError" questionnaireResponseNotFound: $ref: "./examples/responses/GET_QuestionnaireResponse/errors/questionnaire_response_not_found.yaml#/QuestionnaireResponseNotFound" "5XX": @@ -2790,3 +2784,14 @@ components: format: uuid pattern: "^[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}$" example: 74eed847-ca25-4e76-8cf2-f2c2d7842a7a + + AccessRequestID: + in: path + name: id + required: true + description: The unique access request ID of the QuestionnaireResponse to retrieve + schema: + type: string + format: uuid + pattern: "^[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}$" + example: "156e1560-e532-4e2a-85ad-5aeff03dc43e" From 65f5aeecb2546b89596cbe921f8ff58dfbe76996 Mon Sep 17 00:00:00 2001 From: adamclarkson Date: Tue, 14 Oct 2025 14:55:45 +0100 Subject: [PATCH 4/9] NPA-5534: Updated sandbox tests Signed-off-by: adamclarkson --- sandbox/api/app.py | 15 +++++- sandbox/api/constants.py | 1 + sandbox/api/get_questionnaire_response.py | 11 ++--- .../tests/test_get_questionnaire_response.py | 46 +++++++++++++------ ...t_allowed.yaml => method-not-allowed.yaml} | 0 .../validated-relationships-service-api.yaml | 2 +- 6 files changed, 53 insertions(+), 22 deletions(-) rename specification/examples/responses/errors/{method_not_allowed.yaml => method-not-allowed.yaml} (100%) diff --git a/sandbox/api/app.py b/sandbox/api/app.py index 699fe8ab..70afcb8b 100644 --- a/sandbox/api/app.py +++ b/sandbox/api/app.py @@ -10,6 +10,8 @@ from .patch_consent import patch_consent_response from .post_consent import post_consent_response from .post_questionnaire_response import post_questionnaire_response_response +from .utils import generate_response_from_example +from .constants import METHOD_NOT_ALLOWED app = Flask(__name__) basicConfig(level=INFO, format="%(asctime)s - %(message)s") @@ -40,13 +42,24 @@ def get_related_persons() -> Union[dict, tuple]: @app.route(f"/{COMMON_PATH}/QuestionnaireResponse", methods=["GET"]) +@app.route(f"/{COMMON_PATH}/QuestionnaireResponse/", methods=["GET"]) def get_questionnaire_response() -> Union[dict, tuple]: """Sandbox API for GET /QuestionnaireResponse Returns: Union[dict, tuple]: Response for GET /QuestionnaireResponse """ - return get_questionnaire_response_response() + return generate_response_from_example(METHOD_NOT_ALLOWED, 405) + + +@app.route(f"/{COMMON_PATH}/QuestionnaireResponse/", methods=["GET"]) +def get_questionnaire_response_id(identifier: str) -> Union[dict, tuple]: + """Sandbox API for GET /QuestionnaireResponse + + Returns: + Union[dict, tuple]: Response for GET /QuestionnaireResponse + """ + return get_questionnaire_response_response(identifier) @app.route(f"/{COMMON_PATH}/QuestionnaireResponse", methods=["POST"]) diff --git a/sandbox/api/constants.py b/sandbox/api/constants.py index 0f6bdcda..5d044316 100644 --- a/sandbox/api/constants.py +++ b/sandbox/api/constants.py @@ -14,6 +14,7 @@ INVALIDATED_RESOURCE = "./api/examples/errors/invalidated-resource.yaml" MISSING_IDENTIFIER = "./api/examples/errors/missing-identifier.yaml" INVALID_IDENTIFIER = "./api/examples/errors/invalid-identifier.yaml" +METHOD_NOT_ALLOWED = "./api/examples/errors/method-not-allowed.yaml" # GET Consent examples GET_CONSENT__DIRECTORY = "./api/examples/GET_Consent/" diff --git a/sandbox/api/get_questionnaire_response.py b/sandbox/api/get_questionnaire_response.py index 795340d4..71681573 100644 --- a/sandbox/api/get_questionnaire_response.py +++ b/sandbox/api/get_questionnaire_response.py @@ -5,10 +5,10 @@ from .constants import ( GET_QUESTIONNAIRE_RESPONSE__INVALID, - GET_QUESTIONNAIRE_RESPONSE__MISSING, GET_QUESTIONNAIRE_RESPONSE__NOT_FOUND, GET_QUESTIONNAIRE_RESPONSE__SUCCESS, INTERNAL_SERVER_ERROR_EXAMPLE, + METHOD_NOT_ALLOWED ) from .utils import generate_response_from_example @@ -16,20 +16,19 @@ logger = getLogger(__name__) -def get_questionnaire_response_response() -> Union[dict, tuple]: - """Sandbox API for GET /QuestionnaireResponse +def get_questionnaire_response_response(access_request_id: str) -> Union[dict, tuple]: + """Sandbox API for GET /QuestionnaireResponse/{id} Returns: - Union[dict, tuple]: Response for GET /QuestionnaireResponse + Union[dict, tuple]: Response for GET /QuestionnaireResponse/{id} """ try: - access_request_id = request.args.get("ID") if access_request_id == "156e1560-e532-4e2a-85ad-5aeff03dc43e": return generate_response_from_example(GET_QUESTIONNAIRE_RESPONSE__SUCCESS, 200) elif access_request_id == "INVALID": return generate_response_from_example(GET_QUESTIONNAIRE_RESPONSE__INVALID, 400) elif access_request_id == "" or access_request_id is None: - return generate_response_from_example(GET_QUESTIONNAIRE_RESPONSE__MISSING, 400) + return generate_response_from_example(METHOD_NOT_ALLOWED, 405) elif access_request_id == "60d09b82-f4bb-41f9-b41e-767999b4ac9b": return generate_response_from_example(GET_QUESTIONNAIRE_RESPONSE__NOT_FOUND, 404) else: diff --git a/sandbox/api/tests/test_get_questionnaire_response.py b/sandbox/api/tests/test_get_questionnaire_response.py index 72f9ab05..b67f2e5c 100644 --- a/sandbox/api/tests/test_get_questionnaire_response.py +++ b/sandbox/api/tests/test_get_questionnaire_response.py @@ -3,56 +3,74 @@ from flask import Response from json import dumps, loads +from pycparser.plyparser import parameterized + GET_QUESTIONNAIRE_RESPONSE_API_ENDPOINT = "/FHIR/R4/QuestionnaireResponse" @pytest.mark.parametrize( - ("request_args", "response_file_name", "status_code"), + ("path", "response_file_name", "status_code"), [ ( - "ID=156e1560-e532-4e2a-85ad-5aeff03dc43e", + "/156e1560-e532-4e2a-85ad-5aeff03dc43e", "./api/examples/GET_QuestionnaireResponse/success.yaml", 200, ), ( - "ID=INVALID", + "/INVALID", "./api/examples/GET_QuestionnaireResponse/errors/invalid_access_request_id.yaml", 400, ), ( - "ID=", - "./api/examples/GET_QuestionnaireResponse/errors/missing_access_request_id.yaml", - 400, - ), - ( - "ID=60d09b82-f4bb-41f9-b41e-767999b4ac9b", + "/60d09b82-f4bb-41f9-b41e-767999b4ac9b", "./api/examples/GET_QuestionnaireResponse/errors/questionnaire_response_not_found.yaml", 404, ), ( - "ID=INVALID_CODE", + "/INVALID_CODE", "./api/examples/errors/internal-server-error.yaml", 500, ), ], ) @patch("sandbox.api.get_questionnaire_response.generate_response_from_example") -def test_get_questionnaire_response_returns_expected_responses__mocked_utils( +def test_get_questionnaire_response_id_returns_expected_responses__mocked_utils( mock_generate_response_from_example: MagicMock, - request_args: str, + path: str, response_file_name: str, status_code: int, client: object, ) -> None: - """Test GET Consent endpoint.""" + """Test GET /QuestionnaireResponse/{id} endpoint.""" mock_generate_response_from_example.return_value = mocked_response = Response( dumps({"data": "mocked"}), status=status_code, content_type="application/json", ) # Act - response = client.get(f"{GET_QUESTIONNAIRE_RESPONSE_API_ENDPOINT}?{request_args}") + response = client.get(f"{GET_QUESTIONNAIRE_RESPONSE_API_ENDPOINT}{path}") # Assert mock_generate_response_from_example.assert_called_once_with(response_file_name, status_code) assert response.status_code == status_code assert response.json == loads(mocked_response.get_data(as_text=True)) + + +@pytest.mark.parametrize("path", ["/",""]) +@patch("sandbox.api.app.generate_response_from_example") +def test_get_questionnaire_response_without_path_params_return_405_errors( + mock_generate_response_from_example: MagicMock, + path: str, + client: object, +) -> None: + """Test the GET /QuestionnaireResponse endpoint with no path params.""" + mock_generate_response_from_example.return_value = mocked_response = Response( + dumps({"data": "mocked"}), + status=405, + content_type="application/json", + ) + # Act + response = client.get(f"{GET_QUESTIONNAIRE_RESPONSE_API_ENDPOINT}{path}") + # Assert + mock_generate_response_from_example.assert_called_once_with("./api/examples/errors/method-not-allowed.yaml", 405) + assert response.status_code == 405 + assert response.json == loads(mocked_response.get_data(as_text=True)) diff --git a/specification/examples/responses/errors/method_not_allowed.yaml b/specification/examples/responses/errors/method-not-allowed.yaml similarity index 100% rename from specification/examples/responses/errors/method_not_allowed.yaml rename to specification/examples/responses/errors/method-not-allowed.yaml diff --git a/specification/validated-relationships-service-api.yaml b/specification/validated-relationships-service-api.yaml index 83da8353..3981f9a9 100644 --- a/specification/validated-relationships-service-api.yaml +++ b/specification/validated-relationships-service-api.yaml @@ -370,7 +370,7 @@ paths: invalidAccessRequestID: $ref: "./examples/responses/GET_QuestionnaireResponse/errors/invalid_access_request_id.yaml#/InvalidAccessRequestID" missingAccessRequestID: - $ref: "./examples/responses/errors/method_not_allowed.yaml#/MethodNotAllowedError" + $ref: "./examples/responses/errors/method-not-allowed.yaml#/MethodNotAllowedError" questionnaireResponseNotFound: $ref: "./examples/responses/GET_QuestionnaireResponse/errors/questionnaire_response_not_found.yaml#/QuestionnaireResponseNotFound" "5XX": From 7935c837c0b9bf8678e638045157a90550e0de1c Mon Sep 17 00:00:00 2001 From: adamclarkson Date: Tue, 14 Oct 2025 15:14:55 +0100 Subject: [PATCH 5/9] NPA-5534: Updated postman collection and OAS button --- ...ip Service Sandbox.postman_collection.json | 632 +++++++++++++----- .../validated-relationships-service-api.yaml | 2 +- 2 files changed, 460 insertions(+), 174 deletions(-) diff --git a/postman/Validated Relationship Service Sandbox.postman_collection.json b/postman/Validated Relationship Service Sandbox.postman_collection.json index 7522d040..c560b14b 100644 --- a/postman/Validated Relationship Service Sandbox.postman_collection.json +++ b/postman/Validated Relationship Service Sandbox.postman_collection.json @@ -1,11 +1,11 @@ { "info": { - "_postman_id": "4c6e58e9-dd6b-42fc-b6d7-5beac34fa4ea", - "name": "Validated Relationship Service Sandbox 18/09/25", + "_postman_id": "5c759d0a-d924-44ab-8668-3587dcaf27e1", + "name": "Validated Relationship Service Sandbox 14/10/25", "description": "This Postman collection includes example scenarios for each of the Validated Relationship Service (VRS) API endpoints, covering both valid and invalid request scenarios.\n\nThe collection is pointed towards the VRS sandbox environment, which will return a specific example response based on the request sent. All data shown in the requests or responses is test data.\n\nOur sandbox environment only covers the scenarios listed in the Postman collection and is open access. It does not allow you to test authorisation or any scenarios beyond the ones documented.\n\nFull specification is available at [https://digital.nhs.uk/developer/api-catalogue/validated-relationship-service](https://digital.nhs.uk/developer/api-catalogue/validated-relationship-service)", "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", - "_exporter_id": "44536620", - "_collection_link": "https://www.postman.com/ellie-bound1-b2ea016f/workspace/validated-relationship-service-sandbox-18-10-2025/collection/44536620-4c6e58e9-dd6b-42fc-b6d7-5beac34fa4ea?action=share&source=collection_link&creator=44536620" + "_exporter_id": "18067099", + "_collection_link": "https://www.postman.com/lunar-crescent-672573/workspace/validated-relationship-service-14-10-2025/collection/18067099-5c759d0a-d924-44ab-8668-3587dcaf27e1?action=share&source=collection_link&creator=18067099" }, "item": [ { @@ -235,14 +235,13 @@ } ], "url": { - "raw": "{{api_base_url}}/QuestionnaireResponse?ID=156e1560-e532-4e2a-85ad-5aeff03dc43e", - "host": ["{{api_base_url}}"], - "path": ["QuestionnaireResponse"], - "query": [ - { - "key": "ID", - "value": "156e1560-e532-4e2a-85ad-5aeff03dc43e" - } + "raw": "{{api_base_url}}/QuestionnaireResponse/156e1560-e532-4e2a-85ad-5aeff03dc43e", + "host": [ + "{{api_base_url}}" + ], + "path": [ + "QuestionnaireResponse", + "156e1560-e532-4e2a-85ad-5aeff03dc43e" ] }, "description": "Example of Questionnaire Response that will be returned" @@ -257,27 +256,28 @@ "script": { "exec": [ "const expectedResponseBody = {", - " \"resourceType\": \"OperationOutcome\",", " \"issue\": [", " {", - " \"severity\": \"error\",", - " \"code\": \"required\",", + " \"code\": \"not-supported\",", " \"details\": {", " \"coding\": [", " {", - " \"system\": \"https://fhir.nhs.uk/STU3/CodeSystem/Spine-ErrorOrWarningCode-1\",", - " \"code\": \"BAD_REQUEST\",", - " \"display\": \"Bad request\"", + " \"code\": \"METHOD_NOT_ALLOWED\",", + " \"display\": \"The method is not allowed.\",", + " \"system\": \"https://fhir.nhs.uk/R4/CodeSystem/ValidatedRelationships-ErrorOrWarningCode\",", + " \"version\": \"1\"", " }", " ]", " },", - " \"diagnostics\": \"The access request ID parameter is required but was not provided.\"", + " \"diagnostics\": \"The method is not allowed for the requested resource.\",", + " \"severity\": \"error\"", " }", - " ]", + " ],", + " \"resourceType\": \"OperationOutcome\"", "};", "", - "pm.test(\"Status code is 400\", function () {", - " pm.response.to.have.status(400);", + "pm.test(\"Status code is 405\", function () {", + " pm.response.to.have.status(405);", "});", "", "pm.test(\"Should have correct response body\", () => {", @@ -305,9 +305,14 @@ } ], "url": { - "raw": "{{api_base_url}}/QuestionnaireResponse", - "host": ["{{api_base_url}}"], - "path": ["QuestionnaireResponse"] + "raw": "{{api_base_url}}/QuestionnaireResponse/", + "host": [ + "{{api_base_url}}" + ], + "path": [ + "QuestionnaireResponse", + "" + ] }, "description": "Example of an error response when reference code is missing from request" }, @@ -369,14 +374,13 @@ } ], "url": { - "raw": "{{api_base_url}}/QuestionnaireResponse?ID=INVALID", - "host": ["{{api_base_url}}"], - "path": ["QuestionnaireResponse"], - "query": [ - { - "key": "ID", - "value": "INVALID" - } + "raw": "{{api_base_url}}/QuestionnaireResponse/INVALID", + "host": [ + "{{api_base_url}}" + ], + "path": [ + "QuestionnaireResponse", + "INVALID" ] }, "description": "Example of an error response when reference code is invalid" @@ -439,14 +443,13 @@ } ], "url": { - "raw": "{{api_base_url}}/QuestionnaireResponse?ID=60d09b82-f4bb-41f9-b41e-767999b4ac9b", - "host": ["{{api_base_url}}"], - "path": ["QuestionnaireResponse"], - "query": [ - { - "key": "ID", - "value": "60d09b82-f4bb-41f9-b41e-767999b4ac9b" - } + "raw": "{{api_base_url}}/QuestionnaireResponse/60d09b82-f4bb-41f9-b41e-767999b4ac9b", + "host": [ + "{{api_base_url}}" + ], + "path": [ + "QuestionnaireResponse", + "60d09b82-f4bb-41f9-b41e-767999b4ac9b" ] }, "description": "Example of an error response when reference code is not found in database" @@ -532,8 +535,12 @@ }, "url": { "raw": "{{api_base_url}}/QuestionnaireResponse", - "host": ["{{api_base_url}}"], - "path": ["QuestionnaireResponse"] + "host": [ + "{{api_base_url}}" + ], + "path": [ + "QuestionnaireResponse" + ] }, "description": "Example of an adult to child access request with the reference code returned" }, @@ -611,8 +618,12 @@ }, "url": { "raw": "{{api_base_url}}/QuestionnaireResponse", - "host": ["{{api_base_url}}"], - "path": ["QuestionnaireResponse"] + "host": [ + "{{api_base_url}}" + ], + "path": [ + "QuestionnaireResponse" + ] }, "description": "Example of an adult to adult access request where the patient can consent with the reference code returned" }, @@ -675,8 +686,12 @@ }, "url": { "raw": "{{api_base_url}}/QuestionnaireResponse", - "host": ["{{api_base_url}}"], - "path": ["QuestionnaireResponse"] + "host": [ + "{{api_base_url}}" + ], + "path": [ + "QuestionnaireResponse" + ] } }, "response": [] @@ -753,8 +768,12 @@ }, "url": { "raw": "{{api_base_url}}/QuestionnaireResponse", - "host": ["{{api_base_url}}"], - "path": ["QuestionnaireResponse"] + "host": [ + "{{api_base_url}}" + ], + "path": [ + "QuestionnaireResponse" + ] }, "description": "Example of an adult to adult access request where the patient cannot consent with the reference code returned" }, @@ -832,8 +851,12 @@ }, "url": { "raw": "{{api_base_url}}/QuestionnaireResponse", - "host": ["{{api_base_url}}"], - "path": ["QuestionnaireResponse"] + "host": [ + "{{api_base_url}}" + ], + "path": [ + "QuestionnaireResponse" + ] }, "description": "Example of an adult to adult access request where the patient is the applicant with the reference code returned" }, @@ -846,14 +869,18 @@ "listen": "prerequest", "script": { "type": "text/javascript", - "exec": [""] + "exec": [ + "" + ] } }, { "listen": "test", "script": { "type": "text/javascript", - "exec": [""] + "exec": [ + "" + ] } } ] @@ -1011,8 +1038,12 @@ ], "url": { "raw": "{{api_base_url}}/RelatedPerson?identifier=9000000017", - "host": ["{{api_base_url}}"], - "path": ["RelatedPerson"], + "host": [ + "{{api_base_url}}" + ], + "path": [ + "RelatedPerson" + ], "query": [ { "key": "identifier", @@ -1238,8 +1269,12 @@ ], "url": { "raw": "{{api_base_url}}/RelatedPerson?identifier=9000000017&_include=RelatedPerson:patient", - "host": ["{{api_base_url}}"], - "path": ["RelatedPerson"], + "host": [ + "{{api_base_url}}" + ], + "path": [ + "RelatedPerson" + ], "query": [ { "key": "identifier", @@ -1304,8 +1339,12 @@ ], "url": { "raw": "{{api_base_url}}/RelatedPerson?identifier=9000000033", - "host": ["{{api_base_url}}"], - "path": ["RelatedPerson"], + "host": [ + "{{api_base_url}}" + ], + "path": [ + "RelatedPerson" + ], "query": [ { "key": "identifier", @@ -1418,8 +1457,12 @@ ], "url": { "raw": "{{api_base_url}}/RelatedPerson?identifier=9000000017&patient:identifier=9000000009", - "host": ["{{api_base_url}}"], - "path": ["RelatedPerson"], + "host": [ + "{{api_base_url}}" + ], + "path": [ + "RelatedPerson" + ], "query": [ { "key": "identifier", @@ -1568,8 +1611,12 @@ ], "url": { "raw": "{{api_base_url}}/RelatedPerson?identifier=9000000017&patient:identifier=9000000009&_include=RelatedPerson:patient", - "host": ["{{api_base_url}}"], - "path": ["RelatedPerson"], + "host": [ + "{{api_base_url}}" + ], + "path": [ + "RelatedPerson" + ], "query": [ { "key": "identifier", @@ -1652,8 +1699,12 @@ ], "url": { "raw": "{{api_base_url}}/RelatedPerson", - "host": ["{{api_base_url}}"], - "path": ["RelatedPerson"] + "host": [ + "{{api_base_url}}" + ], + "path": [ + "RelatedPerson" + ] }, "description": "Example of an error response when the NHS number is missing" }, @@ -1725,8 +1776,12 @@ ], "url": { "raw": "{{api_base_url}}/RelatedPerson?identifier=900000000", - "host": ["{{api_base_url}}"], - "path": ["RelatedPerson"], + "host": [ + "{{api_base_url}}" + ], + "path": [ + "RelatedPerson" + ], "query": [ { "key": "identifier", @@ -1800,8 +1855,12 @@ ], "url": { "raw": "{{api_base_url}}/RelatedPerson?identifier=https://fhir.nhs.uk/Id/nhs-number|A730675929", - "host": ["{{api_base_url}}"], - "path": ["RelatedPerson"], + "host": [ + "{{api_base_url}}" + ], + "path": [ + "RelatedPerson" + ], "query": [ { "key": "identifier", @@ -1876,8 +1935,12 @@ ], "url": { "raw": "{{api_base_url}}/RelatedPerson?identifier=1000000001", - "host": ["{{api_base_url}}"], - "path": ["RelatedPerson"], + "host": [ + "{{api_base_url}}" + ], + "path": [ + "RelatedPerson" + ], "query": [ { "key": "identifier", @@ -1952,8 +2015,12 @@ ], "url": { "raw": "{{api_base_url}}/RelatedPerson?identifier=9000000041", - "host": ["{{api_base_url}}"], - "path": ["RelatedPerson"], + "host": [ + "{{api_base_url}}" + ], + "path": [ + "RelatedPerson" + ], "query": [ { "key": "identifier", @@ -2366,7 +2433,9 @@ { "listen": "prerequest", "script": { - "exec": [""], + "exec": [ + "" + ], "type": "text/javascript", "packages": {} } @@ -2389,8 +2458,12 @@ }, "url": { "raw": "{{api_base_url}}/Consent?performer:identifier=9000000017&status=active&_include=Consent:performer&_include=Consent:patient", - "host": ["{{api_base_url}}"], - "path": ["Consent"], + "host": [ + "{{api_base_url}}" + ], + "path": [ + "Consent" + ], "query": [ { "key": "performer:identifier", @@ -2611,7 +2684,9 @@ { "listen": "prerequest", "script": { - "exec": [""], + "exec": [ + "" + ], "type": "text/javascript", "packages": {} } @@ -2622,8 +2697,12 @@ "header": [], "url": { "raw": "{{api_base_url}}/Consent?performer:identifier=9000000017&status=inactive", - "host": ["{{api_base_url}}"], - "path": ["Consent"], + "host": [ + "{{api_base_url}}" + ], + "path": [ + "Consent" + ], "query": [ { "key": "performer:identifier", @@ -2999,8 +3078,12 @@ "header": [], "url": { "raw": "{{api_base_url}}/Consent?performer:identifier=9000000017&status=proposed&status=active&_include=Consent:patient", - "host": ["{{api_base_url}}"], - "path": ["Consent"], + "host": [ + "{{api_base_url}}" + ], + "path": [ + "Consent" + ], "query": [ { "key": "performer:identifier", @@ -3304,8 +3387,12 @@ "header": [], "url": { "raw": "{{api_base_url}}/Consent?performer:identifier=9000000022", - "host": ["{{api_base_url}}"], - "path": ["Consent"], + "host": [ + "{{api_base_url}}" + ], + "path": [ + "Consent" + ], "query": [ { "key": "performer:identifier", @@ -3769,8 +3856,12 @@ "header": [], "url": { "raw": "{{api_base_url}}/Consent?performer:identifier=9000000022&_include=Consent:patient", - "host": ["{{api_base_url}}"], - "path": ["Consent"], + "host": [ + "{{api_base_url}}" + ], + "path": [ + "Consent" + ], "query": [ { "key": "performer:identifier", @@ -4185,8 +4276,12 @@ "header": [], "url": { "raw": "{{api_base_url}}/Consent?performer:identifier=9000000022&_include=Consent:performer", - "host": ["{{api_base_url}}"], - "path": ["Consent"], + "host": [ + "{{api_base_url}}" + ], + "path": [ + "Consent" + ], "query": [ { "key": "performer:identifier", @@ -4773,8 +4868,12 @@ "header": [], "url": { "raw": "{{api_base_url}}/Consent?performer:identifier=9000000022&_include=Consent:performer&_include=Consent:patient", - "host": ["{{api_base_url}}"], - "path": ["Consent"], + "host": [ + "{{api_base_url}}" + ], + "path": [ + "Consent" + ], "query": [ { "key": "performer:identifier", @@ -5074,8 +5173,12 @@ "header": [], "url": { "raw": "{{api_base_url}}/Consent?patient:identifier=9000000100", - "host": ["{{api_base_url}}"], - "path": ["Consent"], + "host": [ + "{{api_base_url}}" + ], + "path": [ + "Consent" + ], "query": [ { "key": "patient:identifier", @@ -5542,8 +5645,12 @@ "header": [], "url": { "raw": "{{api_base_url}}/Consent?patient:identifier=9000000100&_include=Consent:performer&_include=Consent:patient", - "host": ["{{api_base_url}}"], - "path": ["Consent"], + "host": [ + "{{api_base_url}}" + ], + "path": [ + "Consent" + ], "query": [ { "key": "patient:identifier", @@ -5962,8 +6069,12 @@ "header": [], "url": { "raw": "{{api_base_url}}/Consent?patient:identifier=9000000100&_include=Consent:performer", - "host": ["{{api_base_url}}"], - "path": ["Consent"], + "host": [ + "{{api_base_url}}" + ], + "path": [ + "Consent" + ], "query": [ { "key": "patient:identifier", @@ -6315,8 +6426,12 @@ "header": [], "url": { "raw": "{{api_base_url}}/Consent?patient:identifier=9000000100&_include=Consent:patient", - "host": ["{{api_base_url}}"], - "path": ["Consent"], + "host": [ + "{{api_base_url}}" + ], + "path": [ + "Consent" + ], "query": [ { "key": "patient:identifier", @@ -6371,8 +6486,12 @@ "header": [], "url": { "raw": "{{api_base_url}}/Consent?performer:identifier=9000000025", - "host": ["{{api_base_url}}"], - "path": ["Consent"], + "host": [ + "{{api_base_url}}" + ], + "path": [ + "Consent" + ], "query": [ { "key": "performer:identifier", @@ -6504,8 +6623,12 @@ "header": [], "url": { "raw": "{{api_base_url}}/Consent?performer:identifier=9000000010", - "host": ["{{api_base_url}}"], - "path": ["Consent"], + "host": [ + "{{api_base_url}}" + ], + "path": [ + "Consent" + ], "query": [ { "key": "performer:identifier", @@ -6731,8 +6854,12 @@ "header": [], "url": { "raw": "{{api_base_url}}/Consent?performer:identifier=9000000010&_include=Consent:performer&_include=Consent:patient", - "host": ["{{api_base_url}}"], - "path": ["Consent"], + "host": [ + "{{api_base_url}}" + ], + "path": [ + "Consent" + ], "query": [ { "key": "performer:identifier", @@ -6872,8 +6999,12 @@ "header": [], "url": { "raw": "{{api_base_url}}/Consent?performer:identifier=9000000019", - "host": ["{{api_base_url}}"], - "path": ["Consent"], + "host": [ + "{{api_base_url}}" + ], + "path": [ + "Consent" + ], "query": [ { "key": "performer:identifier", @@ -7108,8 +7239,12 @@ "header": [], "url": { "raw": "{{api_base_url}}/Consent?performer:identifier=9000000019&_include=Consent:performer&_include=Consent:patient", - "host": ["{{api_base_url}}"], - "path": ["Consent"], + "host": [ + "{{api_base_url}}" + ], + "path": [ + "Consent" + ], "query": [ { "key": "performer:identifier", @@ -7176,8 +7311,12 @@ "header": [], "url": { "raw": "{{api_base_url}}/Consent?performer:identifier=9000000017&status=test", - "host": ["{{api_base_url}}"], - "path": ["Consent"], + "host": [ + "{{api_base_url}}" + ], + "path": [ + "Consent" + ], "query": [ { "key": "performer:identifier", @@ -7244,8 +7383,12 @@ "header": [], "url": { "raw": "{{api_base_url}}/Consent?performer:identifier=9000000019&_include=test", - "host": ["{{api_base_url}}"], - "path": ["Consent"], + "host": [ + "{{api_base_url}}" + ], + "path": [ + "Consent" + ], "query": [ { "key": "performer:identifier", @@ -7313,8 +7456,12 @@ "header": [], "url": { "raw": "{{api_base_url}}/Consent?performer:identifier=9000000999", - "host": ["{{api_base_url}}"], - "path": ["Consent"], + "host": [ + "{{api_base_url}}" + ], + "path": [ + "Consent" + ], "query": [ { "key": "performer:identifier", @@ -7377,8 +7524,12 @@ "header": [], "url": { "raw": "{{api_base_url}}/Consent?performer:identifier=90000009990", - "host": ["{{api_base_url}}"], - "path": ["Consent"], + "host": [ + "{{api_base_url}}" + ], + "path": [ + "Consent" + ], "query": [ { "key": "performer:identifier", @@ -7441,8 +7592,12 @@ "header": [], "url": { "raw": "{{api_base_url}}/Consent?performer:identifier=https://fhir.nhs.uk/Id/nhs-number|1234567890", - "host": ["{{api_base_url}}"], - "path": ["Consent"], + "host": [ + "{{api_base_url}}" + ], + "path": [ + "Consent" + ], "query": [ { "key": "performer:identifier", @@ -7505,8 +7660,12 @@ "header": [], "url": { "raw": "{{api_base_url}}/Consent", - "host": ["{{api_base_url}}"], - "path": ["Consent"] + "host": [ + "{{api_base_url}}" + ], + "path": [ + "Consent" + ] } }, "response": [] @@ -7563,8 +7722,12 @@ "header": [], "url": { "raw": "{{api_base_url}}/Consent?performer:identifier=9000000012", - "host": ["{{api_base_url}}"], - "path": ["Consent"], + "host": [ + "{{api_base_url}}" + ], + "path": [ + "Consent" + ], "query": [ { "key": "performer:identifier", @@ -7630,8 +7793,12 @@ }, "url": { "raw": "{{api_base_url}}/Consent", - "host": ["{{api_base_url}}"], - "path": ["Consent"] + "host": [ + "{{api_base_url}}" + ], + "path": [ + "Consent" + ] } }, "response": [] @@ -7685,8 +7852,12 @@ }, "url": { "raw": "{{api_base_url}}/Consent", - "host": ["{{api_base_url}}"], - "path": ["Consent"] + "host": [ + "{{api_base_url}}" + ], + "path": [ + "Consent" + ] } }, "response": [] @@ -7748,8 +7919,12 @@ }, "url": { "raw": "{{api_base_url}}/Consent", - "host": ["{{api_base_url}}"], - "path": ["Consent"] + "host": [ + "{{api_base_url}}" + ], + "path": [ + "Consent" + ] } }, "response": [] @@ -7811,8 +7986,12 @@ }, "url": { "raw": "{{api_base_url}}/Consent", - "host": ["{{api_base_url}}"], - "path": ["Consent"] + "host": [ + "{{api_base_url}}" + ], + "path": [ + "Consent" + ] } }, "response": [] @@ -7944,8 +8123,13 @@ "header": [], "url": { "raw": "{{api_base_url}}/Consent/74eed847-ca25-4e76-8cf2-f2c2d7842a7a", - "host": ["{{api_base_url}}"], - "path": ["Consent", "74eed847-ca25-4e76-8cf2-f2c2d7842a7a"] + "host": [ + "{{api_base_url}}" + ], + "path": [ + "Consent", + "74eed847-ca25-4e76-8cf2-f2c2d7842a7a" + ] } }, "response": [] @@ -8101,8 +8285,13 @@ "header": [], "url": { "raw": "{{api_base_url}}/Consent/74eed847-ca25-4e76-8cf2-f2c2d7842a7a?_include=Consent:patient", - "host": ["{{api_base_url}}"], - "path": ["Consent", "74eed847-ca25-4e76-8cf2-f2c2d7842a7a"], + "host": [ + "{{api_base_url}}" + ], + "path": [ + "Consent", + "74eed847-ca25-4e76-8cf2-f2c2d7842a7a" + ], "query": [ { "key": "_include", @@ -8246,8 +8435,13 @@ "header": [], "url": { "raw": "{{api_base_url}}/Consent/74eed847-ca25-4e76-8cf2-f2c2d7842a7a?_include=Consent:performer", - "host": ["{{api_base_url}}"], - "path": ["Consent", "74eed847-ca25-4e76-8cf2-f2c2d7842a7a"], + "host": [ + "{{api_base_url}}" + ], + "path": [ + "Consent", + "74eed847-ca25-4e76-8cf2-f2c2d7842a7a" + ], "query": [ { "key": "_include", @@ -8472,8 +8666,13 @@ "header": [], "url": { "raw": "{{api_base_url}}/Consent/74eed847-ca25-4e76-8cf2-f2c2d7842a7a?_include=Consent:performer&_include=Consent:patient", - "host": ["{{api_base_url}}"], - "path": ["Consent", "74eed847-ca25-4e76-8cf2-f2c2d7842a7a"], + "host": [ + "{{api_base_url}}" + ], + "path": [ + "Consent", + "74eed847-ca25-4e76-8cf2-f2c2d7842a7a" + ], "query": [ { "key": "_include", @@ -8609,8 +8808,13 @@ "header": [], "url": { "raw": "{{api_base_url}}/Consent/39df03a2-1b14-4d19-b1dc-d5d8cbf96948", - "host": ["{{api_base_url}}"], - "path": ["Consent", "39df03a2-1b14-4d19-b1dc-d5d8cbf96948"] + "host": [ + "{{api_base_url}}" + ], + "path": [ + "Consent", + "39df03a2-1b14-4d19-b1dc-d5d8cbf96948" + ] } }, "response": [] @@ -8770,8 +8974,13 @@ "header": [], "url": { "raw": "{{api_base_url}}/Consent/39df03a2-1b14-4d19-b1dc-d5d8cbf96948?_include=Consent:patient", - "host": ["{{api_base_url}}"], - "path": ["Consent", "39df03a2-1b14-4d19-b1dc-d5d8cbf96948"], + "host": [ + "{{api_base_url}}" + ], + "path": [ + "Consent", + "39df03a2-1b14-4d19-b1dc-d5d8cbf96948" + ], "query": [ { "key": "_include", @@ -8914,8 +9123,13 @@ "header": [], "url": { "raw": "{{api_base_url}}/Consent/39df03a2-1b14-4d19-b1dc-d5d8cbf96948?_include=Consent:performer", - "host": ["{{api_base_url}}"], - "path": ["Consent", "39df03a2-1b14-4d19-b1dc-d5d8cbf96948"], + "host": [ + "{{api_base_url}}" + ], + "path": [ + "Consent", + "39df03a2-1b14-4d19-b1dc-d5d8cbf96948" + ], "query": [ { "key": "_include", @@ -9150,8 +9364,13 @@ "header": [], "url": { "raw": "{{api_base_url}}/Consent/39df03a2-1b14-4d19-b1dc-d5d8cbf96948?_include=Consent:performer&_include=Consent:patient", - "host": ["{{api_base_url}}"], - "path": ["Consent", "39df03a2-1b14-4d19-b1dc-d5d8cbf96948"], + "host": [ + "{{api_base_url}}" + ], + "path": [ + "Consent", + "39df03a2-1b14-4d19-b1dc-d5d8cbf96948" + ], "query": [ { "key": "_include", @@ -9214,8 +9433,13 @@ "header": [], "url": { "raw": "{{api_base_url}}/Consent/invalid-identifier", - "host": ["{{api_base_url}}"], - "path": ["Consent", "invalid-identifier"] + "host": [ + "{{api_base_url}}" + ], + "path": [ + "Consent", + "invalid-identifier" + ] } }, "response": [] @@ -9269,8 +9493,13 @@ "header": [], "url": { "raw": "{{api_base_url}}/Consent/39df03a2-1b14-4d19-b1dc-d5d8cbf96948?_include=Consent:invalid", - "host": ["{{api_base_url}}"], - "path": ["Consent", "39df03a2-1b14-4d19-b1dc-d5d8cbf96948"], + "host": [ + "{{api_base_url}}" + ], + "path": [ + "Consent", + "39df03a2-1b14-4d19-b1dc-d5d8cbf96948" + ], "query": [ { "key": "_include", @@ -9329,8 +9558,13 @@ "header": [], "url": { "raw": "{{api_base_url}}/Consent/74eed847-ca25-4e76-8cf2-f2c2d7842a7a?_unknown=true", - "host": ["{{api_base_url}}"], - "path": ["Consent", "74eed847-ca25-4e76-8cf2-f2c2d7842a7a"], + "host": [ + "{{api_base_url}}" + ], + "path": [ + "Consent", + "74eed847-ca25-4e76-8cf2-f2c2d7842a7a" + ], "query": [ { "key": "_unknown", @@ -9389,8 +9623,13 @@ "header": [], "url": { "raw": "{{api_base_url}}/Consent/a0922245-1072-40c3-8f4e-a7490c10d365", - "host": ["{{api_base_url}}"], - "path": ["Consent", "a0922245-1072-40c3-8f4e-a7490c10d365"] + "host": [ + "{{api_base_url}}" + ], + "path": [ + "Consent", + "a0922245-1072-40c3-8f4e-a7490c10d365" + ] } }, "response": [] @@ -9446,8 +9685,13 @@ }, "url": { "raw": "{{api_base_url}}/Consent/74eed847-ca25-4e76-8cf2-f2c2d7842a7a", - "host": ["{{api_base_url}}"], - "path": ["Consent", "74eed847-ca25-4e76-8cf2-f2c2d7842a7a"] + "host": [ + "{{api_base_url}}" + ], + "path": [ + "Consent", + "74eed847-ca25-4e76-8cf2-f2c2d7842a7a" + ] }, "description": "Valid patch changing status to 'active'" }, @@ -9498,8 +9742,13 @@ }, "url": { "raw": "{{api_base_url}}/Consent/6b71ac92-baa3-4b76-b0f5-a601257e2722", - "host": ["{{api_base_url}}"], - "path": ["Consent", "6b71ac92-baa3-4b76-b0f5-a601257e2722"] + "host": [ + "{{api_base_url}}" + ], + "path": [ + "Consent", + "6b71ac92-baa3-4b76-b0f5-a601257e2722" + ] }, "description": "Valid patch modifying the role end date" }, @@ -9550,8 +9799,13 @@ }, "url": { "raw": "{{api_base_url}}/Consent/43003db8-ffcd-4bd6-ab2f-b49b9656f9e5", - "host": ["{{api_base_url}}"], - "path": ["Consent", "43003db8-ffcd-4bd6-ab2f-b49b9656f9e5"] + "host": [ + "{{api_base_url}}" + ], + "path": [ + "Consent", + "43003db8-ffcd-4bd6-ab2f-b49b9656f9e5" + ] }, "description": "Valid patch modifying the role end date" }, @@ -9613,8 +9867,13 @@ }, "url": { "raw": "{{api_base_url}}/Consent/78c35330-fa2f-4934-a5dd-fff847f38de5", - "host": ["{{api_base_url}}"], - "path": ["Consent", "78c35330-fa2f-4934-a5dd-fff847f38de5"] + "host": [ + "{{api_base_url}}" + ], + "path": [ + "Consent", + "78c35330-fa2f-4934-a5dd-fff847f38de5" + ] }, "description": "Patch with invalid status value" }, @@ -9676,8 +9935,13 @@ }, "url": { "raw": "{{api_base_url}}/Consent/01abb0c5-b1ac-499d-9655-9cd0b8d3588f", - "host": ["{{api_base_url}}"], - "path": ["Consent", "01abb0c5-b1ac-499d-9655-9cd0b8d3588f"] + "host": [ + "{{api_base_url}}" + ], + "path": [ + "Consent", + "01abb0c5-b1ac-499d-9655-9cd0b8d3588f" + ] }, "description": "Patch targeting non-existent element" }, @@ -9739,8 +10003,13 @@ }, "url": { "raw": "{{api_base_url}}/Consent/0000000", - "host": ["{{api_base_url}}"], - "path": ["Consent", "0000000"] + "host": [ + "{{api_base_url}}" + ], + "path": [ + "Consent", + "0000000" + ] }, "description": "Patch for non-existent Consent" }, @@ -9802,8 +10071,13 @@ }, "url": { "raw": "{{api_base_url}}/Consent/849ea584-2318-471b-a24c-cee1b5ad0137", - "host": ["{{api_base_url}}"], - "path": ["Consent", "849ea584-2318-471b-a24c-cee1b5ad0137"] + "host": [ + "{{api_base_url}}" + ], + "path": [ + "Consent", + "849ea584-2318-471b-a24c-cee1b5ad0137" + ] }, "description": "Malformed JSON patch document" }, @@ -9865,8 +10139,13 @@ }, "url": { "raw": "{{api_base_url}}/Consent/7b7f47b8-96e5-43eb-b733-283bf1449f2c", - "host": ["{{api_base_url}}"], - "path": ["Consent", "7b7f47b8-96e5-43eb-b733-283bf1449f2c"] + "host": [ + "{{api_base_url}}" + ], + "path": [ + "Consent", + "7b7f47b8-96e5-43eb-b733-283bf1449f2c" + ] } }, "response": [] @@ -9927,8 +10206,13 @@ }, "url": { "raw": "{{api_base_url}}/Consent/51fb4df5-815a-45cd-8427-04d6558336b7", - "host": ["{{api_base_url}}"], - "path": ["Consent", "51fb4df5-815a-45cd-8427-04d6558336b7"] + "host": [ + "{{api_base_url}}" + ], + "path": [ + "Consent", + "51fb4df5-815a-45cd-8427-04d6558336b7" + ] } }, "response": [] @@ -9943,7 +10227,9 @@ "script": { "type": "text/javascript", "packages": {}, - "exec": [""] + "exec": [ + "" + ] } }, { @@ -9965,4 +10251,4 @@ "value": "https://sandbox.api.service.nhs.uk/validated-relationships/FHIR/R4" } ] -} +} \ No newline at end of file diff --git a/specification/validated-relationships-service-api.yaml b/specification/validated-relationships-service-api.yaml index 3981f9a9..3c4c25af 100644 --- a/specification/validated-relationships-service-api.yaml +++ b/specification/validated-relationships-service-api.yaml @@ -141,7 +141,7 @@ info: * only covers a limited set of scenarios * is open access, so does not allow you to test authorisation - [Run In Postman](https://app.getpostman.com/run-collection/44536620-c011ca09-3246-4d9c-870e-33ebd0629114?action=collection%2Ffork&source=rip_markdown&collection-url=entityId%3D44536620-c011ca09-3246-4d9c-870e-33ebd0629114%26entityType%3Dcollection%26workspaceId%3D81756490-ef07-4f09-9861-3c601a39729e) + [Run In Postman](https://app.getpostman.com/run-collection/18067099-5c759d0a-d924-44ab-8668-3587dcaf27e1?action=collection%2Ffork&source=rip_markdown&collection-url=entityId%3D18067099-5c759d0a-d924-44ab-8668-3587dcaf27e1%26entityType%3Dcollection%26workspaceId%3D1ee72d72-3355-4213-a165-a79aa2ab1de8) ### Integration testing From 1cd60bdd6ccefb655bde169600c37749af897118 Mon Sep 17 00:00:00 2001 From: adamclarkson Date: Tue, 14 Oct 2025 15:30:41 +0100 Subject: [PATCH 6/9] NPA-5534: sandbox formatting update --- sandbox/api/constants.py | 130 ++++++++++++------ sandbox/api/get_consent_by_id.py | 8 +- sandbox/api/get_questionnaire_response.py | 14 +- sandbox/api/patch_consent.py | 20 ++- sandbox/api/post_consent.py | 20 ++- sandbox/api/post_questionnaire_response.py | 16 ++- sandbox/api/tests/test_get_consent.py | 16 ++- sandbox/api/tests/test_get_consent_by_id.py | 12 +- .../tests/test_get_questionnaire_response.py | 10 +- sandbox/api/tests/test_get_related_person.py | 4 +- sandbox/api/tests/test_patch_consent.py | 28 +++- sandbox/api/tests/test_post_consent.py | 8 +- .../tests/test_post_questionnaire_response.py | 13 +- sandbox/api/tests/test_utils.py | 4 +- sandbox/api/utils.py | 43 ++++-- 15 files changed, 247 insertions(+), 99 deletions(-) diff --git a/sandbox/api/constants.py b/sandbox/api/constants.py index 5d044316..0d174ed1 100644 --- a/sandbox/api/constants.py +++ b/sandbox/api/constants.py @@ -10,7 +10,9 @@ # Common examples INTERNAL_SERVER_ERROR_EXAMPLE = "./api/examples/errors/internal-server-error.yaml" -BAD_REQUEST_INCLUDE_PARAM_INVALID = "./api/examples/errors/invalid-include-parameter.yaml" +BAD_REQUEST_INCLUDE_PARAM_INVALID = ( + "./api/examples/errors/invalid-include-parameter.yaml" +) INVALIDATED_RESOURCE = "./api/examples/errors/invalidated-resource.yaml" MISSING_IDENTIFIER = "./api/examples/errors/missing-identifier.yaml" INVALID_IDENTIFIER = "./api/examples/errors/invalid-identifier.yaml" @@ -27,7 +29,9 @@ GET_CONSENT__FILTERED_RELATIONSHIPS_STATUS_PROPOSED_ACTIVE = ( f"{GET_CONSENT__DIRECTORY}filtered-relationships-status-proposed-active.yaml" ) -GET_CONSENT__MULTIPLE_RELATIONSHIPS = f"{GET_CONSENT__DIRECTORY}multiple-relationships.yaml" +GET_CONSENT__MULTIPLE_RELATIONSHIPS = ( + f"{GET_CONSENT__DIRECTORY}multiple-relationships.yaml" +) GET_CONSENT__MULTIPLE_RELATIONSHIPS_INCLUDE_BOTH = ( f"{GET_CONSENT__DIRECTORY}multiple-relationships-include-performer-patient.yaml" ) @@ -38,88 +42,124 @@ f"{GET_CONSENT__DIRECTORY}multiple-relationships-include-performer.yaml" ) GET_CONSENT__NO_RELATIONSHIPS = f"{GET_CONSENT__DIRECTORY}no-relationships.yaml" -GET_CONSENT__SINGLE_CONSENTING_ADULT_RELATIONSHIP = f"{GET_CONSENT__DIRECTORY}single-consenting-adult-relationship.yaml" -GET_CONSENT__SINGLE_CONSENTING_ADULT_RELATIONSHIP_INCLUDE_BOTH = ( - f"{GET_CONSENT__DIRECTORY}single-consenting-adult-relationship-include-performer-patient.yaml" +GET_CONSENT__SINGLE_CONSENTING_ADULT_RELATIONSHIP = ( + f"{GET_CONSENT__DIRECTORY}single-consenting-adult-relationship.yaml" ) +GET_CONSENT__SINGLE_CONSENTING_ADULT_RELATIONSHIP_INCLUDE_BOTH = f"{GET_CONSENT__DIRECTORY}single-consenting-adult-relationship-include-performer-patient.yaml" GET_CONSENT__SINGLE_CONSENTING_ADULT_RELATIONSHIP_INCLUDE_PATIENT = ( f"{GET_CONSENT__DIRECTORY}single-consenting-adult-relationship-include-patient.yaml" ) -GET_CONSENT__SINGLE_CONSENTING_ADULT_RELATIONSHIP_INCLUDE_PERFORMER = ( - f"{GET_CONSENT__DIRECTORY}single-consenting-adult-relationship-include-performer.yaml" -) -GET_CONSENT__SINGLE_MOTHER_CHILD_RELATIONSHIP = f"{GET_CONSENT__DIRECTORY}single-mother-child-relationship.yaml" -GET_CONSENT__SINGLE_MOTHER_CHILD_RELATIONSHIP_INCLUDE_BOTH = ( - f"{GET_CONSENT__DIRECTORY}single-mother-child-relationship-include-performer-patient.yaml" +GET_CONSENT__SINGLE_CONSENTING_ADULT_RELATIONSHIP_INCLUDE_PERFORMER = f"{GET_CONSENT__DIRECTORY}single-consenting-adult-relationship-include-performer.yaml" +GET_CONSENT__SINGLE_MOTHER_CHILD_RELATIONSHIP = ( + f"{GET_CONSENT__DIRECTORY}single-mother-child-relationship.yaml" ) +GET_CONSENT__SINGLE_MOTHER_CHILD_RELATIONSHIP_INCLUDE_BOTH = f"{GET_CONSENT__DIRECTORY}single-mother-child-relationship-include-performer-patient.yaml" GET_CONSENT__SINGLE_MOTHER_CHILD_RELATIONSHIP_INCLUDE_PATIENT = ( f"{GET_CONSENT__DIRECTORY}single-mother-child-relationship-include-patient.yaml" ) GET_CONSENT__SINGLE_MOTHER_CHILD_RELATIONSHIP_INCLUDE_PERFORMER = ( f"{GET_CONSENT__DIRECTORY}single-mother-child-relationship-include-performer.yaml" ) -GET_CONSENT__STATUS_PARAM_INVALID = f"{GET_CONSENT__DIRECTORY}errors/invalid-status-parameter.yaml" +GET_CONSENT__STATUS_PARAM_INVALID = ( + f"{GET_CONSENT__DIRECTORY}errors/invalid-status-parameter.yaml" +) GET_CONSENT__MULTIPLE_RELATIONSHIPS_SINGLE_PATIENT = ( f"{GET_CONSENT__DIRECTORY}multiple-relationships-single-patient.yaml" ) -GET_CONSENT__MULTIPLE_RELATIONSHIPS_SINGLE_PATIENT_INCLUDE_PERFORMER = ( - f"{GET_CONSENT__DIRECTORY}multiple-relationships-single-patient-include-performer.yaml" -) -GET_CONSENT__MULTIPLE_RELATIONSHIPS_SINGLE_PATIENT_INCLUDE_PATIENT = ( - f"{GET_CONSENT__DIRECTORY}multiple-relationships-single-patient-include-patient.yaml" -) -GET_CONSENT__MULTIPLE_RELATIONSHIPS_SINGLE_PATIENT_INCLUDE_BOTH = ( - f"{GET_CONSENT__DIRECTORY}multiple-relationships-single-patient-include-performer-patient.yaml" -) +GET_CONSENT__MULTIPLE_RELATIONSHIPS_SINGLE_PATIENT_INCLUDE_PERFORMER = f"{GET_CONSENT__DIRECTORY}multiple-relationships-single-patient-include-performer.yaml" +GET_CONSENT__MULTIPLE_RELATIONSHIPS_SINGLE_PATIENT_INCLUDE_PATIENT = f"{GET_CONSENT__DIRECTORY}multiple-relationships-single-patient-include-patient.yaml" +GET_CONSENT__MULTIPLE_RELATIONSHIPS_SINGLE_PATIENT_INCLUDE_BOTH = f"{GET_CONSENT__DIRECTORY}multiple-relationships-single-patient-include-performer-patient.yaml" # GET Consent by ID -GET_CONSENT_BY_ID__INVALID_ID_ERROR = f"{GET_CONSENT__DIRECTORY}ID/errors/invalid-id.yaml" +GET_CONSENT_BY_ID__INVALID_ID_ERROR = ( + f"{GET_CONSENT__DIRECTORY}ID/errors/invalid-id.yaml" +) # POST Consent POST_CONSENT__DIRECTORY = "./api/examples/POST_Consent/" POST_CONSENT__SUCCESS = f"{POST_CONSENT__DIRECTORY}success.yaml" -POST_CONSENT__DUPLICATE_RELATIONSHIP_ERROR = f"{POST_CONSENT__DIRECTORY}errors/duplicate_relationship_error.yaml" -POST_CONSENT__PERFORMER_IDENTIFIER_ERROR = f"{POST_CONSENT__DIRECTORY}errors/invalid_performer_identifier_error.yaml" +POST_CONSENT__DUPLICATE_RELATIONSHIP_ERROR = ( + f"{POST_CONSENT__DIRECTORY}errors/duplicate_relationship_error.yaml" +) +POST_CONSENT__PERFORMER_IDENTIFIER_ERROR = ( + f"{POST_CONSENT__DIRECTORY}errors/invalid_performer_identifier_error.yaml" +) # PATCH Consent PATCH_CONSENT__DIRECTORY = "./api/examples/PATCH_Consent/" PATCH_CONSENT__SUCCESS = f"{PATCH_CONSENT__DIRECTORY}success.yaml" -PATCH_CONSENT__INVALID_PATCH_FORMAT = f"{PATCH_CONSENT__DIRECTORY}errors/invalid_patch_format.yaml" +PATCH_CONSENT__INVALID_PATCH_FORMAT = ( + f"{PATCH_CONSENT__DIRECTORY}errors/invalid_patch_format.yaml" +) PATCH_CONSENT__INVALID_PATH = f"{PATCH_CONSENT__DIRECTORY}errors/invalid_path.yaml" -PATCH_CONSENT__INVALID_STATUS_CODE = f"{PATCH_CONSENT__DIRECTORY}errors/invalid_status_code.yaml" -PATCH_CONSENT__INVALID_STATUS_REASON = f"{PATCH_CONSENT__DIRECTORY}errors/invalid_status_reason.yaml" -PATCH_CONSENT__RESOURCE_NOT_FOUND = f"{PATCH_CONSENT__DIRECTORY}errors/resource_not_found.yaml" -PATCH_CONSENT__INVALID_STATE_TRANSITION = f"{PATCH_CONSENT__DIRECTORY}errors/invalid_state_transition.yaml" +PATCH_CONSENT__INVALID_STATUS_CODE = ( + f"{PATCH_CONSENT__DIRECTORY}errors/invalid_status_code.yaml" +) +PATCH_CONSENT__INVALID_STATUS_REASON = ( + f"{PATCH_CONSENT__DIRECTORY}errors/invalid_status_reason.yaml" +) +PATCH_CONSENT__RESOURCE_NOT_FOUND = ( + f"{PATCH_CONSENT__DIRECTORY}errors/resource_not_found.yaml" +) +PATCH_CONSENT__INVALID_STATE_TRANSITION = ( + f"{PATCH_CONSENT__DIRECTORY}errors/invalid_state_transition.yaml" +) # POST QuestionnaireResponse POST_QUESTIONNAIRE_RESPONSE_DIRECTORY = "./api/examples/POST_QuestionnaireResponse/" -POST_QUESTIONNAIRE_RESPONSE__SUCCESS = f"{POST_QUESTIONNAIRE_RESPONSE_DIRECTORY}success.yaml" +POST_QUESTIONNAIRE_RESPONSE__SUCCESS = ( + f"{POST_QUESTIONNAIRE_RESPONSE_DIRECTORY}success.yaml" +) POST_QUESTIONNAIRE_RESPONSE__DUPLICATE_RELATIONSHIP_ERROR = ( f"{POST_QUESTIONNAIRE_RESPONSE_DIRECTORY}errors/duplicate_relationship_error.yaml" ) # GET QuestionnaireResponse GET_QUESTIONNAIRE_RESPONSE_DIRECTORY = "./api/examples/GET_QuestionnaireResponse/" -GET_QUESTIONNAIRE_RESPONSE__SUCCESS = f"{GET_QUESTIONNAIRE_RESPONSE_DIRECTORY}success.yaml" -GET_QUESTIONNAIRE_RESPONSE__INVALID = f"{GET_QUESTIONNAIRE_RESPONSE_DIRECTORY}errors/invalid_access_request_id.yaml" -GET_QUESTIONNAIRE_RESPONSE__MISSING = f"{GET_QUESTIONNAIRE_RESPONSE_DIRECTORY}errors/missing_access_request_id.yaml" -GET_QUESTIONNAIRE_RESPONSE__NOT_FOUND = ( - f"{GET_QUESTIONNAIRE_RESPONSE_DIRECTORY}errors/questionnaire_response_not_found.yaml" +GET_QUESTIONNAIRE_RESPONSE__SUCCESS = ( + f"{GET_QUESTIONNAIRE_RESPONSE_DIRECTORY}success.yaml" +) +GET_QUESTIONNAIRE_RESPONSE__INVALID = ( + f"{GET_QUESTIONNAIRE_RESPONSE_DIRECTORY}errors/invalid_access_request_id.yaml" +) +GET_QUESTIONNAIRE_RESPONSE__MISSING = ( + f"{GET_QUESTIONNAIRE_RESPONSE_DIRECTORY}errors/missing_access_request_id.yaml" ) +GET_QUESTIONNAIRE_RESPONSE__NOT_FOUND = f"{GET_QUESTIONNAIRE_RESPONSE_DIRECTORY}errors/questionnaire_response_not_found.yaml" # GET RelatedPerson RELATED_DIRECTORY = "./api/examples/GET_RelatedPerson/" -RELATED__ERROR_IDENTIFIER_MISSING = f"{RELATED_DIRECTORY}errors/invalid-identifier-missing.yaml" -RELATED__ERROR_IDENTIFIER_SYSTEM = f"{RELATED_DIRECTORY}errors/invalid-identifier-system.yaml" +RELATED__ERROR_IDENTIFIER_MISSING = ( + f"{RELATED_DIRECTORY}errors/invalid-identifier-missing.yaml" +) +RELATED__ERROR_IDENTIFIER_SYSTEM = ( + f"{RELATED_DIRECTORY}errors/invalid-identifier-system.yaml" +) RELATED__ERROR_IDENTIFIER = f"{RELATED_DIRECTORY}errors/invalid-identifier.yaml" -RELATED__ERROR_PATIENT_IDENTIFIER = f"{RELATED_DIRECTORY}errors/invalid-patient-identifier.yaml" +RELATED__ERROR_PATIENT_IDENTIFIER = ( + f"{RELATED_DIRECTORY}errors/invalid-patient-identifier.yaml" +) RELATED__EMPTY_RESPONSE = f"{RELATED_DIRECTORY}empty_response.yaml" RELATED__LIST_RELATIONSHIP = f"{RELATED_DIRECTORY}list_relationship_9000000017.yaml" -RELATED__LIST_RELATIONSHIP_WITH_INCLUDE = f"{RELATED_DIRECTORY}list_relationship_9000000017_include.yaml" -RELATED__LIST_CHILD_RELATIONSHIP = f"{RELATED_DIRECTORY}list_relationship_9000000042.yaml" -RELATED__LIST_CHILD_RELATIONSHIP_WITH_INCLUDE = f"{RELATED_DIRECTORY}list_relationship_9000000042_include.yaml" -RELATED__VERIFY_RELATIONSHIP_09 = f"{RELATED_DIRECTORY}verify_relationship_9000000009.yaml" -RELATED__VERIFY_RELATIONSHIP_09_WITH_INCLUDE = f"{RELATED_DIRECTORY}verify_relationship_9000000009_include.yaml" -RELATED__VERIFY_RELATIONSHIP_25 = f"{RELATED_DIRECTORY}verify_relationship_9000000025.yaml" -RELATED__VERIFY_RELATIONSHIP_25_WITH_INCLUDE = f"{RELATED_DIRECTORY}verify_relationship_9000000025_include.yaml" +RELATED__LIST_RELATIONSHIP_WITH_INCLUDE = ( + f"{RELATED_DIRECTORY}list_relationship_9000000017_include.yaml" +) +RELATED__LIST_CHILD_RELATIONSHIP = ( + f"{RELATED_DIRECTORY}list_relationship_9000000042.yaml" +) +RELATED__LIST_CHILD_RELATIONSHIP_WITH_INCLUDE = ( + f"{RELATED_DIRECTORY}list_relationship_9000000042_include.yaml" +) +RELATED__VERIFY_RELATIONSHIP_09 = ( + f"{RELATED_DIRECTORY}verify_relationship_9000000009.yaml" +) +RELATED__VERIFY_RELATIONSHIP_09_WITH_INCLUDE = ( + f"{RELATED_DIRECTORY}verify_relationship_9000000009_include.yaml" +) +RELATED__VERIFY_RELATIONSHIP_25 = ( + f"{RELATED_DIRECTORY}verify_relationship_9000000025.yaml" +) +RELATED__VERIFY_RELATIONSHIP_25_WITH_INCLUDE = ( + f"{RELATED_DIRECTORY}verify_relationship_9000000025_include.yaml" +) RELATED__EMPTY_RESPONSE = f"{RELATED_DIRECTORY}empty_response_9000000033.yaml" diff --git a/sandbox/api/get_consent_by_id.py b/sandbox/api/get_consent_by_id.py index ae4e24c1..4a9c2124 100644 --- a/sandbox/api/get_consent_by_id.py +++ b/sandbox/api/get_consent_by_id.py @@ -31,7 +31,9 @@ def get_consent_by_id_response(identifier: str) -> Union[dict, tuple]: try: params = request.args.to_dict() if "_include" not in params and len(params) > 0: - return generate_response_from_example(BAD_REQUEST_INCLUDE_PARAM_INVALID, 422) + return generate_response_from_example( + BAD_REQUEST_INCLUDE_PARAM_INVALID, 422 + ) else: _include = request.args.getlist("_include") @@ -54,7 +56,9 @@ def get_consent_by_id_response(identifier: str) -> Union[dict, tuple]: elif identifier == "a0922245-1072-40c3-8f4e-a7490c10d365": return generate_response_from_example(INVALIDATED_RESOURCE, 404) else: - return generate_response_from_example(GET_CONSENT_BY_ID__INVALID_ID_ERROR, 400) + return generate_response_from_example( + GET_CONSENT_BY_ID__INVALID_ID_ERROR, 400 + ) except Exception: logger.exception("An error occurred while processing the request") diff --git a/sandbox/api/get_questionnaire_response.py b/sandbox/api/get_questionnaire_response.py index 71681573..8e2cda08 100644 --- a/sandbox/api/get_questionnaire_response.py +++ b/sandbox/api/get_questionnaire_response.py @@ -8,7 +8,7 @@ GET_QUESTIONNAIRE_RESPONSE__NOT_FOUND, GET_QUESTIONNAIRE_RESPONSE__SUCCESS, INTERNAL_SERVER_ERROR_EXAMPLE, - METHOD_NOT_ALLOWED + METHOD_NOT_ALLOWED, ) from .utils import generate_response_from_example @@ -24,13 +24,19 @@ def get_questionnaire_response_response(access_request_id: str) -> Union[dict, t """ try: if access_request_id == "156e1560-e532-4e2a-85ad-5aeff03dc43e": - return generate_response_from_example(GET_QUESTIONNAIRE_RESPONSE__SUCCESS, 200) + return generate_response_from_example( + GET_QUESTIONNAIRE_RESPONSE__SUCCESS, 200 + ) elif access_request_id == "INVALID": - return generate_response_from_example(GET_QUESTIONNAIRE_RESPONSE__INVALID, 400) + return generate_response_from_example( + GET_QUESTIONNAIRE_RESPONSE__INVALID, 400 + ) elif access_request_id == "" or access_request_id is None: return generate_response_from_example(METHOD_NOT_ALLOWED, 405) elif access_request_id == "60d09b82-f4bb-41f9-b41e-767999b4ac9b": - return generate_response_from_example(GET_QUESTIONNAIRE_RESPONSE__NOT_FOUND, 404) + return generate_response_from_example( + GET_QUESTIONNAIRE_RESPONSE__NOT_FOUND, 404 + ) else: raise ValueError("Invalid access request ID") except Exception: diff --git a/sandbox/api/patch_consent.py b/sandbox/api/patch_consent.py index 822c3d06..b1770bbc 100644 --- a/sandbox/api/patch_consent.py +++ b/sandbox/api/patch_consent.py @@ -45,7 +45,9 @@ def patch_consent_response(id: str) -> Union[dict, tuple]: elif id == "849ea584-2318-471b-a24c-cee1b5ad0137": # Invalid patch format - return generate_response_from_example(PATCH_CONSENT__INVALID_PATCH_FORMAT, 400) + return generate_response_from_example( + PATCH_CONSENT__INVALID_PATCH_FORMAT, 400 + ) elif id == "01abb0c5-b1ac-499d-9655-9cd0b8d3588f": # Invalid path @@ -53,19 +55,27 @@ def patch_consent_response(id: str) -> Union[dict, tuple]: elif id == "78c35330-fa2f-4934-a5dd-fff847f38de5": # Invalid status code - return generate_response_from_example(PATCH_CONSENT__INVALID_STATUS_CODE, 422) + return generate_response_from_example( + PATCH_CONSENT__INVALID_STATUS_CODE, 422 + ) elif id == "51fb4df5-815a-45cd-8427-04d6558336b7": # Invalid status reason - return generate_response_from_example(PATCH_CONSENT__INVALID_STATUS_REASON, 422) + return generate_response_from_example( + PATCH_CONSENT__INVALID_STATUS_REASON, 422 + ) elif id == "7b7f47b8-96e5-43eb-b733-283bf1449f2c": # Invalid state transition - return generate_response_from_example(PATCH_CONSENT__INVALID_STATE_TRANSITION, 422) + return generate_response_from_example( + PATCH_CONSENT__INVALID_STATE_TRANSITION, 422 + ) else: # Resource not found - return generate_response_from_example(PATCH_CONSENT__RESOURCE_NOT_FOUND, 404) + return generate_response_from_example( + PATCH_CONSENT__RESOURCE_NOT_FOUND, 404 + ) except Exception: # Handle any general error diff --git a/sandbox/api/post_consent.py b/sandbox/api/post_consent.py index cd15be78..cd6f9681 100644 --- a/sandbox/api/post_consent.py +++ b/sandbox/api/post_consent.py @@ -11,7 +11,9 @@ ) from .utils import generate_response_from_example -CONSENT_APP_BASE_PATH = "https://sandbox.api.service.nhs.uk/validated-relationships/FHIR/R4/Consent" +CONSENT_APP_BASE_PATH = ( + "https://sandbox.api.service.nhs.uk/validated-relationships/FHIR/R4/Consent" +) basicConfig(level=INFO, format="%(asctime)s - %(message)s") logger = getLogger(__name__) @@ -32,15 +34,23 @@ def post_consent_response() -> Union[dict, tuple]: # Successful parent-child proxy creation # Successful adult-adult proxy creation if patient_identifier == "9000000009" or patient_identifier == "9000000017": - header = {"location": f"{CONSENT_APP_BASE_PATH}/90b9863e-e33c-4895-a333-fd0ea0e23205"} - response = generate_response_from_example(POST_CONSENT__SUCCESS, 201, headers=header) + header = { + "location": f"{CONSENT_APP_BASE_PATH}/90b9863e-e33c-4895-a333-fd0ea0e23205" + } + response = generate_response_from_example( + POST_CONSENT__SUCCESS, 201, headers=header + ) # Duplicate relationship elif patient_identifier == "9000000049": - response = generate_response_from_example(POST_CONSENT__DUPLICATE_RELATIONSHIP_ERROR, 409) + response = generate_response_from_example( + POST_CONSENT__DUPLICATE_RELATIONSHIP_ERROR, 409 + ) # Invalid performer NHS number elif patient_identifier == "9000000000": - response = generate_response_from_example(POST_CONSENT__PERFORMER_IDENTIFIER_ERROR, 422) + response = generate_response_from_example( + POST_CONSENT__PERFORMER_IDENTIFIER_ERROR, 422 + ) else: # Out of scope errors raise ValueError("Invalid Request") diff --git a/sandbox/api/post_questionnaire_response.py b/sandbox/api/post_questionnaire_response.py index da5cfde1..76c001fe 100644 --- a/sandbox/api/post_questionnaire_response.py +++ b/sandbox/api/post_questionnaire_response.py @@ -10,9 +10,7 @@ ) from .utils import generate_response_from_example -QUESTIONNAIRE_RESPONSE_APP_BASE_PATH = ( - "https://sandbox.api.service.nhs.uk/validated-relationships/FHIR/R4/QuestionnaireResponse" -) +QUESTIONNAIRE_RESPONSE_APP_BASE_PATH = "https://sandbox.api.service.nhs.uk/validated-relationships/FHIR/R4/QuestionnaireResponse" basicConfig(level=INFO, format="%(asctime)s - %(message)s") logger = getLogger(__name__) @@ -32,11 +30,17 @@ def post_questionnaire_response_response() -> Union[dict, tuple]: # Successful questionnaire response if source_identifier in ["9000000009", "9000000017"]: - header = {"location": f"{QUESTIONNAIRE_RESPONSE_APP_BASE_PATH}?ID=156e1560-e532-4e2a-85ad-5aeff03dc43e"} - response = generate_response_from_example(POST_QUESTIONNAIRE_RESPONSE__SUCCESS, 200, headers=header) + header = { + "location": f"{QUESTIONNAIRE_RESPONSE_APP_BASE_PATH}?ID=156e1560-e532-4e2a-85ad-5aeff03dc43e" + } + response = generate_response_from_example( + POST_QUESTIONNAIRE_RESPONSE__SUCCESS, 200, headers=header + ) # Duplicate relationship elif source_identifier == "9000000049": - response = generate_response_from_example(POST_QUESTIONNAIRE_RESPONSE__DUPLICATE_RELATIONSHIP_ERROR, 409) + response = generate_response_from_example( + POST_QUESTIONNAIRE_RESPONSE__DUPLICATE_RELATIONSHIP_ERROR, 409 + ) else: # Out of scope errors raise ValueError("Invalid Request") diff --git a/sandbox/api/tests/test_get_consent.py b/sandbox/api/tests/test_get_consent.py index c027b4d9..e20ca4f8 100644 --- a/sandbox/api/tests/test_get_consent.py +++ b/sandbox/api/tests/test_get_consent.py @@ -40,7 +40,9 @@ def test_get_consent_returns_expected_responses__mocked_get_consent( # Act response = client.get(f"{CONSENT_API_ENDPOINT}?{request_args}") # Assert - mock_generate_response_from_example.assert_called_once_with(response_file_name, status_code) + mock_generate_response_from_example.assert_called_once_with( + response_file_name, status_code + ) assert response.status_code == status_code assert response.json == loads(mocked_response.get_data(as_text=True)) @@ -212,7 +214,9 @@ def test_get_consent_returns_expected_responses__mocked_utils( # Act response = client.get(f"{CONSENT_API_ENDPOINT}?{request_args}") # Assert - mock_generate_response_from_example.assert_called_once_with(response_file_name, status_code) + mock_generate_response_from_example.assert_called_once_with( + response_file_name, status_code + ) assert response.status_code == status_code assert response.json == loads(mocked_response.get_data(as_text=True)) @@ -227,6 +231,10 @@ def test_get_consent__500_internal_server_error( """Test Consent endpoint.""" mock_remove_system.side_effect = Exception("Test exception") # Act - client.get(f"{CONSENT_API_ENDPOINT}?performer:identifier=9000000015&status=active&_include=Consent:performer") + client.get( + f"{CONSENT_API_ENDPOINT}?performer:identifier=9000000015&status=active&_include=Consent:performer" + ) # Assert - mock_generate_response_from_example.assert_called_once_with("./api/examples/errors/internal-server-error.yaml", 500) + mock_generate_response_from_example.assert_called_once_with( + "./api/examples/errors/internal-server-error.yaml", 500 + ) diff --git a/sandbox/api/tests/test_get_consent_by_id.py b/sandbox/api/tests/test_get_consent_by_id.py index d7eb5907..4d377510 100644 --- a/sandbox/api/tests/test_get_consent_by_id.py +++ b/sandbox/api/tests/test_get_consent_by_id.py @@ -56,7 +56,9 @@ def test_get_consent_by_id_returns_expected_responses__mocked_get_consent_by_id( response = client.get(f"{CONSENT_API_ENDPOINT}/{consent_id}?{include_params}") # import pdb; pdb.set_trace() # Assert - mock_generate_response_from_example.assert_called_once_with(response_file_name, status_code) + mock_generate_response_from_example.assert_called_once_with( + response_file_name, status_code + ) assert response.status_code == status_code assert response.json == loads(mocked_response.get_data(as_text=True)) @@ -133,7 +135,9 @@ def test_get_consent_by_id_returns_expected_responses__mocked_utils( response = client.get(f"{CONSENT_API_ENDPOINT}/{consent_id}?{include_params}") # import pdb; pdb.set_trace() # Assert - mock_generate_response_from_example.assert_called_once_with(response_file_name, status_code) + mock_generate_response_from_example.assert_called_once_with( + response_file_name, status_code + ) assert response.status_code == status_code assert response.json == loads(mocked_response.get_data(as_text=True)) @@ -150,4 +154,6 @@ def test_get_consent_by_id__500_internal_server_error( # Act client.get(f"{CONSENT_API_ENDPOINT}/74eed847-ca25-4e76-8cf2-f2c2d7842a7a") # Assert - mock_generate_response_from_example.assert_called_once_with("./api/examples/errors/internal-server-error.yaml", 500) + mock_generate_response_from_example.assert_called_once_with( + "./api/examples/errors/internal-server-error.yaml", 500 + ) diff --git a/sandbox/api/tests/test_get_questionnaire_response.py b/sandbox/api/tests/test_get_questionnaire_response.py index b67f2e5c..551d0eb6 100644 --- a/sandbox/api/tests/test_get_questionnaire_response.py +++ b/sandbox/api/tests/test_get_questionnaire_response.py @@ -50,12 +50,14 @@ def test_get_questionnaire_response_id_returns_expected_responses__mocked_utils( # Act response = client.get(f"{GET_QUESTIONNAIRE_RESPONSE_API_ENDPOINT}{path}") # Assert - mock_generate_response_from_example.assert_called_once_with(response_file_name, status_code) + mock_generate_response_from_example.assert_called_once_with( + response_file_name, status_code + ) assert response.status_code == status_code assert response.json == loads(mocked_response.get_data(as_text=True)) -@pytest.mark.parametrize("path", ["/",""]) +@pytest.mark.parametrize("path", ["/", ""]) @patch("sandbox.api.app.generate_response_from_example") def test_get_questionnaire_response_without_path_params_return_405_errors( mock_generate_response_from_example: MagicMock, @@ -71,6 +73,8 @@ def test_get_questionnaire_response_without_path_params_return_405_errors( # Act response = client.get(f"{GET_QUESTIONNAIRE_RESPONSE_API_ENDPOINT}{path}") # Assert - mock_generate_response_from_example.assert_called_once_with("./api/examples/errors/method-not-allowed.yaml", 405) + mock_generate_response_from_example.assert_called_once_with( + "./api/examples/errors/method-not-allowed.yaml", 405 + ) assert response.status_code == 405 assert response.json == loads(mocked_response.get_data(as_text=True)) diff --git a/sandbox/api/tests/test_get_related_person.py b/sandbox/api/tests/test_get_related_person.py index 99f621f6..082ba3fd 100644 --- a/sandbox/api/tests/test_get_related_person.py +++ b/sandbox/api/tests/test_get_related_person.py @@ -116,6 +116,8 @@ def test_related_person( # Act response = client.get(f"{RELATED_PERSON_API_ENDPOINT}?{request_args}") # Assert - mock_generate_response_from_example.assert_called_once_with(response_file_name, status_code) + mock_generate_response_from_example.assert_called_once_with( + response_file_name, status_code + ) assert response.status_code == status_code assert response.json == loads(mocked_response.get_data(as_text=True)) diff --git a/sandbox/api/tests/test_patch_consent.py b/sandbox/api/tests/test_patch_consent.py index c8c086e0..54b22f54 100644 --- a/sandbox/api/tests/test_patch_consent.py +++ b/sandbox/api/tests/test_patch_consent.py @@ -23,11 +23,27 @@ ("74eed847-ca25-4e76-8cf2-f2c2d7842a7a", PATCH_CONSENT__SUCCESS, 200), ("6b71ac92-baa3-4b76-b0f5-a601257e2722", PATCH_CONSENT__SUCCESS, 200), ("43003db8-ffcd-4bd6-ab2f-b49b9656f9e5", PATCH_CONSENT__SUCCESS, 200), - ("849ea584-2318-471b-a24c-cee1b5ad0137", PATCH_CONSENT__INVALID_PATCH_FORMAT, 400), + ( + "849ea584-2318-471b-a24c-cee1b5ad0137", + PATCH_CONSENT__INVALID_PATCH_FORMAT, + 400, + ), ("01abb0c5-b1ac-499d-9655-9cd0b8d3588f", PATCH_CONSENT__INVALID_PATH, 400), - ("78c35330-fa2f-4934-a5dd-fff847f38de5", PATCH_CONSENT__INVALID_STATUS_CODE, 422), - ("51fb4df5-815a-45cd-8427-04d6558336b7", PATCH_CONSENT__INVALID_STATUS_REASON, 422), - ("7b7f47b8-96e5-43eb-b733-283bf1449f2c", PATCH_CONSENT__INVALID_STATE_TRANSITION, 422), + ( + "78c35330-fa2f-4934-a5dd-fff847f38de5", + PATCH_CONSENT__INVALID_STATUS_CODE, + 422, + ), + ( + "51fb4df5-815a-45cd-8427-04d6558336b7", + PATCH_CONSENT__INVALID_STATUS_REASON, + 422, + ), + ( + "7b7f47b8-96e5-43eb-b733-283bf1449f2c", + PATCH_CONSENT__INVALID_STATE_TRANSITION, + 422, + ), ("xxxxxxxx", PATCH_CONSENT__RESOURCE_NOT_FOUND, 404), ("12345678", PATCH_CONSENT__RESOURCE_NOT_FOUND, 404), ], @@ -55,6 +71,8 @@ def test_patch_consent_on_request_returns_expected_response( json = [{"op": "replace", "path": "/status", "value": "inactive"}] response = client.patch(CONSENT_API_ENDPOINT + f"/{nhs_num}", json=json) # Assert - mock_generate_response_from_example.assert_called_once_with(response_file_name, status_code) + mock_generate_response_from_example.assert_called_once_with( + response_file_name, status_code + ) assert response.status_code == status_code assert response.json == loads(mocked_response.get_data(as_text=True)) diff --git a/sandbox/api/tests/test_post_consent.py b/sandbox/api/tests/test_post_consent.py index 936cd596..4de19178 100644 --- a/sandbox/api/tests/test_post_consent.py +++ b/sandbox/api/tests/test_post_consent.py @@ -55,9 +55,13 @@ def test_post_consent_when_valid_returns_expected_response( mock_generate_response_from_example.assert_called_once_with( response_file_name, status_code, - headers={"location": f"https://sandbox.api.service.nhs.uk/validated-relationships/FHIR/R4/Consent/{id}"}, + headers={ + "location": f"https://sandbox.api.service.nhs.uk/validated-relationships/FHIR/R4/Consent/{id}" + }, ) else: - mock_generate_response_from_example.assert_called_once_with(response_file_name, status_code) + mock_generate_response_from_example.assert_called_once_with( + response_file_name, status_code + ) assert response.status_code == status_code assert response.json == loads(mocked_response.get_data(as_text=True)) diff --git a/sandbox/api/tests/test_post_questionnaire_response.py b/sandbox/api/tests/test_post_questionnaire_response.py index 7851f8b4..4c3f7f26 100644 --- a/sandbox/api/tests/test_post_questionnaire_response.py +++ b/sandbox/api/tests/test_post_questionnaire_response.py @@ -59,7 +59,10 @@ def test_post_questionnaire_response( status=status_code, content_type="application/json", ) - json = {"resourceType": "QuestionnaireResponse", "source": {"identifier": {"value": nhs_num}}} + json = { + "resourceType": "QuestionnaireResponse", + "source": {"identifier": {"value": nhs_num}}, + } # Act response = client.post(QUESTIONNAIRE_RESPONSE_API_ENDPOINT, json=json) # Assert @@ -67,9 +70,13 @@ def test_post_questionnaire_response( mock_generate_response_from_example.assert_called_once_with( response_file_name, status_code, - headers={"location": f"{SANDBOX_API_URL}{QUESTIONNAIRE_RESPONSE_API_ENDPOINT}?ID={id}"}, + headers={ + "location": f"{SANDBOX_API_URL}{QUESTIONNAIRE_RESPONSE_API_ENDPOINT}?ID={id}" + }, ) else: - mock_generate_response_from_example.assert_called_once_with(response_file_name, status_code) + mock_generate_response_from_example.assert_called_once_with( + response_file_name, status_code + ) assert response.status_code == status_code assert response.json == loads(mocked_response.get_data(as_text=True)) diff --git a/sandbox/api/tests/test_utils.py b/sandbox/api/tests/test_utils.py index 233befab..08286d80 100644 --- a/sandbox/api/tests/test_utils.py +++ b/sandbox/api/tests/test_utils.py @@ -8,7 +8,9 @@ @patch(f"{FILE_PATH}.open") def test_get_response(mock_open: MagicMock) -> None: # Arrange - mock_open.return_value.__enter__.return_value.read.return_value = '{"data": "mocked"}' + mock_open.return_value.__enter__.return_value.read.return_value = ( + '{"data": "mocked"}' + ) file_name = "./api/responses/GET_RelatedPerson/identifier.json" # Act response = load_json_file(file_name) diff --git a/sandbox/api/utils.py b/sandbox/api/utils.py index 563f5a9f..096b9bd0 100644 --- a/sandbox/api/utils.py +++ b/sandbox/api/utils.py @@ -80,18 +80,23 @@ def check_for_get_consent_errors(request: Request) -> Optional[tuple]: patient_identifier = request.args.get("patient:identifier") if not performer_identifier and not patient_identifier: - return generate_response_from_example("./api/examples/GET_Consent/errors/missing-identifier.yaml", 400) + return generate_response_from_example( + "./api/examples/GET_Consent/errors/missing-identifier.yaml", 400 + ) for identifier in [performer_identifier, patient_identifier]: identifier_without_system = remove_system(identifier) if identifier and len(identifier_without_system) != 10: # invalid identifier - return generate_response_from_example("./api/examples/GET_Consent/errors/invalid-identifier.yaml", 422) + return generate_response_from_example( + "./api/examples/GET_Consent/errors/invalid-identifier.yaml", 422 + ) elif ( isinstance(identifier, str) and "|" in identifier - and "https://fhir.nhs.uk/Id/nhs-number" == identifier.split("|", maxsplit=2)[0] + and "https://fhir.nhs.uk/Id/nhs-number" + == identifier.split("|", maxsplit=2)[0] ): # invalid identifier system return generate_response_from_example( @@ -100,7 +105,9 @@ def check_for_get_consent_errors(request: Request) -> Optional[tuple]: ) elif identifier_without_system == "9000000012": # invalid status - return generate_response_from_example(f"{GET_CONSENT_ERRORS}/gp-practice-not-found.yaml", 404) + return generate_response_from_example( + f"{GET_CONSENT_ERRORS}/gp-practice-not-found.yaml", 404 + ) def check_for_empty(identifier: str, patient_identifier: str) -> Response: @@ -153,7 +160,9 @@ def check_for_validate( return generate_response_from_example(base_file, 200) -def check_for_list(value: str, identifier: str, include: str, base_file: str, inc_file: str) -> Response: +def check_for_list( + value: str, identifier: str, include: str, base_file: str, inc_file: str +) -> Response: """Check for a list relationship response for a given NHS number Args: @@ -204,7 +213,9 @@ def remove_system(identifier: Any) -> str: return "" -def generate_response_from_example(example_path: str, status_code: int, headers: dict = None) -> Response: +def generate_response_from_example( + example_path: str, status_code: int, headers: dict = None +) -> Response: """Converts an example file (yaml) to a response Args: @@ -259,7 +270,11 @@ def check_for_consent_include_params( else: logger.error("No consent:patient example provided") return generate_response_from_example(INTERNAL_SERVER_ERROR_EXAMPLE, 500) - elif len(_include) == 2 and CONSENT_PATIENT in _include and CONSENT_PERFORMER in _include: + elif ( + len(_include) == 2 + and CONSENT_PATIENT in _include + and CONSENT_PERFORMER in _include + ): return generate_response_from_example(include_both_response_yaml, 200) else: return generate_response_from_example(BAD_REQUEST_INCLUDE_PARAM_INVALID, 422) @@ -287,13 +302,21 @@ def check_for_consent_filtering( if status == [] or status is None: return generate_response_from_example(INVALIDATED_RESOURCE, 404) if status == ["active"]: - if len(_include) == 2 and CONSENT_PERFORMER in _include and CONSENT_PERFORMER in _include: - return generate_response_from_example(status_active_with_details_response_yaml, 200) + if ( + len(_include) == 2 + and CONSENT_PERFORMER in _include + and CONSENT_PERFORMER in _include + ): + return generate_response_from_example( + status_active_with_details_response_yaml, 200 + ) else: return generate_response_from_example(INVALIDATED_RESOURCE, 404) elif status == ["inactive"]: return generate_response_from_example(status_inactive_response_yaml, 200) elif len(status) == 2 and "active" in status and "proposed" in status: - return generate_response_from_example(status_proposed_and_active_response_yaml, 200) + return generate_response_from_example( + status_proposed_and_active_response_yaml, 200 + ) else: return generate_response_from_example(GET_CONSENT__STATUS_PARAM_INVALID, 422) From 347907ca0462f941a50d886572146983e2b910ca Mon Sep 17 00:00:00 2001 From: adamclarkson Date: Tue, 14 Oct 2025 15:32:15 +0100 Subject: [PATCH 7/9] NPA-5534: sandbox reformat --- sandbox/api/constants.py | 130 ++++++------------ sandbox/api/get_consent_by_id.py | 8 +- sandbox/api/get_questionnaire_response.py | 12 +- sandbox/api/patch_consent.py | 20 +-- sandbox/api/post_consent.py | 20 +-- sandbox/api/post_questionnaire_response.py | 16 +-- sandbox/api/tests/test_get_consent.py | 16 +-- sandbox/api/tests/test_get_consent_by_id.py | 12 +- .../tests/test_get_questionnaire_response.py | 8 +- sandbox/api/tests/test_get_related_person.py | 4 +- sandbox/api/tests/test_patch_consent.py | 4 +- sandbox/api/tests/test_post_consent.py | 8 +- .../tests/test_post_questionnaire_response.py | 8 +- sandbox/api/tests/test_utils.py | 4 +- sandbox/api/utils.py | 43 ++---- 15 files changed, 92 insertions(+), 221 deletions(-) diff --git a/sandbox/api/constants.py b/sandbox/api/constants.py index 0d174ed1..5d044316 100644 --- a/sandbox/api/constants.py +++ b/sandbox/api/constants.py @@ -10,9 +10,7 @@ # Common examples INTERNAL_SERVER_ERROR_EXAMPLE = "./api/examples/errors/internal-server-error.yaml" -BAD_REQUEST_INCLUDE_PARAM_INVALID = ( - "./api/examples/errors/invalid-include-parameter.yaml" -) +BAD_REQUEST_INCLUDE_PARAM_INVALID = "./api/examples/errors/invalid-include-parameter.yaml" INVALIDATED_RESOURCE = "./api/examples/errors/invalidated-resource.yaml" MISSING_IDENTIFIER = "./api/examples/errors/missing-identifier.yaml" INVALID_IDENTIFIER = "./api/examples/errors/invalid-identifier.yaml" @@ -29,9 +27,7 @@ GET_CONSENT__FILTERED_RELATIONSHIPS_STATUS_PROPOSED_ACTIVE = ( f"{GET_CONSENT__DIRECTORY}filtered-relationships-status-proposed-active.yaml" ) -GET_CONSENT__MULTIPLE_RELATIONSHIPS = ( - f"{GET_CONSENT__DIRECTORY}multiple-relationships.yaml" -) +GET_CONSENT__MULTIPLE_RELATIONSHIPS = f"{GET_CONSENT__DIRECTORY}multiple-relationships.yaml" GET_CONSENT__MULTIPLE_RELATIONSHIPS_INCLUDE_BOTH = ( f"{GET_CONSENT__DIRECTORY}multiple-relationships-include-performer-patient.yaml" ) @@ -42,124 +38,88 @@ f"{GET_CONSENT__DIRECTORY}multiple-relationships-include-performer.yaml" ) GET_CONSENT__NO_RELATIONSHIPS = f"{GET_CONSENT__DIRECTORY}no-relationships.yaml" -GET_CONSENT__SINGLE_CONSENTING_ADULT_RELATIONSHIP = ( - f"{GET_CONSENT__DIRECTORY}single-consenting-adult-relationship.yaml" +GET_CONSENT__SINGLE_CONSENTING_ADULT_RELATIONSHIP = f"{GET_CONSENT__DIRECTORY}single-consenting-adult-relationship.yaml" +GET_CONSENT__SINGLE_CONSENTING_ADULT_RELATIONSHIP_INCLUDE_BOTH = ( + f"{GET_CONSENT__DIRECTORY}single-consenting-adult-relationship-include-performer-patient.yaml" ) -GET_CONSENT__SINGLE_CONSENTING_ADULT_RELATIONSHIP_INCLUDE_BOTH = f"{GET_CONSENT__DIRECTORY}single-consenting-adult-relationship-include-performer-patient.yaml" GET_CONSENT__SINGLE_CONSENTING_ADULT_RELATIONSHIP_INCLUDE_PATIENT = ( f"{GET_CONSENT__DIRECTORY}single-consenting-adult-relationship-include-patient.yaml" ) -GET_CONSENT__SINGLE_CONSENTING_ADULT_RELATIONSHIP_INCLUDE_PERFORMER = f"{GET_CONSENT__DIRECTORY}single-consenting-adult-relationship-include-performer.yaml" -GET_CONSENT__SINGLE_MOTHER_CHILD_RELATIONSHIP = ( - f"{GET_CONSENT__DIRECTORY}single-mother-child-relationship.yaml" +GET_CONSENT__SINGLE_CONSENTING_ADULT_RELATIONSHIP_INCLUDE_PERFORMER = ( + f"{GET_CONSENT__DIRECTORY}single-consenting-adult-relationship-include-performer.yaml" +) +GET_CONSENT__SINGLE_MOTHER_CHILD_RELATIONSHIP = f"{GET_CONSENT__DIRECTORY}single-mother-child-relationship.yaml" +GET_CONSENT__SINGLE_MOTHER_CHILD_RELATIONSHIP_INCLUDE_BOTH = ( + f"{GET_CONSENT__DIRECTORY}single-mother-child-relationship-include-performer-patient.yaml" ) -GET_CONSENT__SINGLE_MOTHER_CHILD_RELATIONSHIP_INCLUDE_BOTH = f"{GET_CONSENT__DIRECTORY}single-mother-child-relationship-include-performer-patient.yaml" GET_CONSENT__SINGLE_MOTHER_CHILD_RELATIONSHIP_INCLUDE_PATIENT = ( f"{GET_CONSENT__DIRECTORY}single-mother-child-relationship-include-patient.yaml" ) GET_CONSENT__SINGLE_MOTHER_CHILD_RELATIONSHIP_INCLUDE_PERFORMER = ( f"{GET_CONSENT__DIRECTORY}single-mother-child-relationship-include-performer.yaml" ) -GET_CONSENT__STATUS_PARAM_INVALID = ( - f"{GET_CONSENT__DIRECTORY}errors/invalid-status-parameter.yaml" -) +GET_CONSENT__STATUS_PARAM_INVALID = f"{GET_CONSENT__DIRECTORY}errors/invalid-status-parameter.yaml" GET_CONSENT__MULTIPLE_RELATIONSHIPS_SINGLE_PATIENT = ( f"{GET_CONSENT__DIRECTORY}multiple-relationships-single-patient.yaml" ) -GET_CONSENT__MULTIPLE_RELATIONSHIPS_SINGLE_PATIENT_INCLUDE_PERFORMER = f"{GET_CONSENT__DIRECTORY}multiple-relationships-single-patient-include-performer.yaml" -GET_CONSENT__MULTIPLE_RELATIONSHIPS_SINGLE_PATIENT_INCLUDE_PATIENT = f"{GET_CONSENT__DIRECTORY}multiple-relationships-single-patient-include-patient.yaml" -GET_CONSENT__MULTIPLE_RELATIONSHIPS_SINGLE_PATIENT_INCLUDE_BOTH = f"{GET_CONSENT__DIRECTORY}multiple-relationships-single-patient-include-performer-patient.yaml" +GET_CONSENT__MULTIPLE_RELATIONSHIPS_SINGLE_PATIENT_INCLUDE_PERFORMER = ( + f"{GET_CONSENT__DIRECTORY}multiple-relationships-single-patient-include-performer.yaml" +) +GET_CONSENT__MULTIPLE_RELATIONSHIPS_SINGLE_PATIENT_INCLUDE_PATIENT = ( + f"{GET_CONSENT__DIRECTORY}multiple-relationships-single-patient-include-patient.yaml" +) +GET_CONSENT__MULTIPLE_RELATIONSHIPS_SINGLE_PATIENT_INCLUDE_BOTH = ( + f"{GET_CONSENT__DIRECTORY}multiple-relationships-single-patient-include-performer-patient.yaml" +) # GET Consent by ID -GET_CONSENT_BY_ID__INVALID_ID_ERROR = ( - f"{GET_CONSENT__DIRECTORY}ID/errors/invalid-id.yaml" -) +GET_CONSENT_BY_ID__INVALID_ID_ERROR = f"{GET_CONSENT__DIRECTORY}ID/errors/invalid-id.yaml" # POST Consent POST_CONSENT__DIRECTORY = "./api/examples/POST_Consent/" POST_CONSENT__SUCCESS = f"{POST_CONSENT__DIRECTORY}success.yaml" -POST_CONSENT__DUPLICATE_RELATIONSHIP_ERROR = ( - f"{POST_CONSENT__DIRECTORY}errors/duplicate_relationship_error.yaml" -) -POST_CONSENT__PERFORMER_IDENTIFIER_ERROR = ( - f"{POST_CONSENT__DIRECTORY}errors/invalid_performer_identifier_error.yaml" -) +POST_CONSENT__DUPLICATE_RELATIONSHIP_ERROR = f"{POST_CONSENT__DIRECTORY}errors/duplicate_relationship_error.yaml" +POST_CONSENT__PERFORMER_IDENTIFIER_ERROR = f"{POST_CONSENT__DIRECTORY}errors/invalid_performer_identifier_error.yaml" # PATCH Consent PATCH_CONSENT__DIRECTORY = "./api/examples/PATCH_Consent/" PATCH_CONSENT__SUCCESS = f"{PATCH_CONSENT__DIRECTORY}success.yaml" -PATCH_CONSENT__INVALID_PATCH_FORMAT = ( - f"{PATCH_CONSENT__DIRECTORY}errors/invalid_patch_format.yaml" -) +PATCH_CONSENT__INVALID_PATCH_FORMAT = f"{PATCH_CONSENT__DIRECTORY}errors/invalid_patch_format.yaml" PATCH_CONSENT__INVALID_PATH = f"{PATCH_CONSENT__DIRECTORY}errors/invalid_path.yaml" -PATCH_CONSENT__INVALID_STATUS_CODE = ( - f"{PATCH_CONSENT__DIRECTORY}errors/invalid_status_code.yaml" -) -PATCH_CONSENT__INVALID_STATUS_REASON = ( - f"{PATCH_CONSENT__DIRECTORY}errors/invalid_status_reason.yaml" -) -PATCH_CONSENT__RESOURCE_NOT_FOUND = ( - f"{PATCH_CONSENT__DIRECTORY}errors/resource_not_found.yaml" -) -PATCH_CONSENT__INVALID_STATE_TRANSITION = ( - f"{PATCH_CONSENT__DIRECTORY}errors/invalid_state_transition.yaml" -) +PATCH_CONSENT__INVALID_STATUS_CODE = f"{PATCH_CONSENT__DIRECTORY}errors/invalid_status_code.yaml" +PATCH_CONSENT__INVALID_STATUS_REASON = f"{PATCH_CONSENT__DIRECTORY}errors/invalid_status_reason.yaml" +PATCH_CONSENT__RESOURCE_NOT_FOUND = f"{PATCH_CONSENT__DIRECTORY}errors/resource_not_found.yaml" +PATCH_CONSENT__INVALID_STATE_TRANSITION = f"{PATCH_CONSENT__DIRECTORY}errors/invalid_state_transition.yaml" # POST QuestionnaireResponse POST_QUESTIONNAIRE_RESPONSE_DIRECTORY = "./api/examples/POST_QuestionnaireResponse/" -POST_QUESTIONNAIRE_RESPONSE__SUCCESS = ( - f"{POST_QUESTIONNAIRE_RESPONSE_DIRECTORY}success.yaml" -) +POST_QUESTIONNAIRE_RESPONSE__SUCCESS = f"{POST_QUESTIONNAIRE_RESPONSE_DIRECTORY}success.yaml" POST_QUESTIONNAIRE_RESPONSE__DUPLICATE_RELATIONSHIP_ERROR = ( f"{POST_QUESTIONNAIRE_RESPONSE_DIRECTORY}errors/duplicate_relationship_error.yaml" ) # GET QuestionnaireResponse GET_QUESTIONNAIRE_RESPONSE_DIRECTORY = "./api/examples/GET_QuestionnaireResponse/" -GET_QUESTIONNAIRE_RESPONSE__SUCCESS = ( - f"{GET_QUESTIONNAIRE_RESPONSE_DIRECTORY}success.yaml" -) -GET_QUESTIONNAIRE_RESPONSE__INVALID = ( - f"{GET_QUESTIONNAIRE_RESPONSE_DIRECTORY}errors/invalid_access_request_id.yaml" -) -GET_QUESTIONNAIRE_RESPONSE__MISSING = ( - f"{GET_QUESTIONNAIRE_RESPONSE_DIRECTORY}errors/missing_access_request_id.yaml" +GET_QUESTIONNAIRE_RESPONSE__SUCCESS = f"{GET_QUESTIONNAIRE_RESPONSE_DIRECTORY}success.yaml" +GET_QUESTIONNAIRE_RESPONSE__INVALID = f"{GET_QUESTIONNAIRE_RESPONSE_DIRECTORY}errors/invalid_access_request_id.yaml" +GET_QUESTIONNAIRE_RESPONSE__MISSING = f"{GET_QUESTIONNAIRE_RESPONSE_DIRECTORY}errors/missing_access_request_id.yaml" +GET_QUESTIONNAIRE_RESPONSE__NOT_FOUND = ( + f"{GET_QUESTIONNAIRE_RESPONSE_DIRECTORY}errors/questionnaire_response_not_found.yaml" ) -GET_QUESTIONNAIRE_RESPONSE__NOT_FOUND = f"{GET_QUESTIONNAIRE_RESPONSE_DIRECTORY}errors/questionnaire_response_not_found.yaml" # GET RelatedPerson RELATED_DIRECTORY = "./api/examples/GET_RelatedPerson/" -RELATED__ERROR_IDENTIFIER_MISSING = ( - f"{RELATED_DIRECTORY}errors/invalid-identifier-missing.yaml" -) -RELATED__ERROR_IDENTIFIER_SYSTEM = ( - f"{RELATED_DIRECTORY}errors/invalid-identifier-system.yaml" -) +RELATED__ERROR_IDENTIFIER_MISSING = f"{RELATED_DIRECTORY}errors/invalid-identifier-missing.yaml" +RELATED__ERROR_IDENTIFIER_SYSTEM = f"{RELATED_DIRECTORY}errors/invalid-identifier-system.yaml" RELATED__ERROR_IDENTIFIER = f"{RELATED_DIRECTORY}errors/invalid-identifier.yaml" -RELATED__ERROR_PATIENT_IDENTIFIER = ( - f"{RELATED_DIRECTORY}errors/invalid-patient-identifier.yaml" -) +RELATED__ERROR_PATIENT_IDENTIFIER = f"{RELATED_DIRECTORY}errors/invalid-patient-identifier.yaml" RELATED__EMPTY_RESPONSE = f"{RELATED_DIRECTORY}empty_response.yaml" RELATED__LIST_RELATIONSHIP = f"{RELATED_DIRECTORY}list_relationship_9000000017.yaml" -RELATED__LIST_RELATIONSHIP_WITH_INCLUDE = ( - f"{RELATED_DIRECTORY}list_relationship_9000000017_include.yaml" -) -RELATED__LIST_CHILD_RELATIONSHIP = ( - f"{RELATED_DIRECTORY}list_relationship_9000000042.yaml" -) -RELATED__LIST_CHILD_RELATIONSHIP_WITH_INCLUDE = ( - f"{RELATED_DIRECTORY}list_relationship_9000000042_include.yaml" -) -RELATED__VERIFY_RELATIONSHIP_09 = ( - f"{RELATED_DIRECTORY}verify_relationship_9000000009.yaml" -) -RELATED__VERIFY_RELATIONSHIP_09_WITH_INCLUDE = ( - f"{RELATED_DIRECTORY}verify_relationship_9000000009_include.yaml" -) -RELATED__VERIFY_RELATIONSHIP_25 = ( - f"{RELATED_DIRECTORY}verify_relationship_9000000025.yaml" -) -RELATED__VERIFY_RELATIONSHIP_25_WITH_INCLUDE = ( - f"{RELATED_DIRECTORY}verify_relationship_9000000025_include.yaml" -) +RELATED__LIST_RELATIONSHIP_WITH_INCLUDE = f"{RELATED_DIRECTORY}list_relationship_9000000017_include.yaml" +RELATED__LIST_CHILD_RELATIONSHIP = f"{RELATED_DIRECTORY}list_relationship_9000000042.yaml" +RELATED__LIST_CHILD_RELATIONSHIP_WITH_INCLUDE = f"{RELATED_DIRECTORY}list_relationship_9000000042_include.yaml" +RELATED__VERIFY_RELATIONSHIP_09 = f"{RELATED_DIRECTORY}verify_relationship_9000000009.yaml" +RELATED__VERIFY_RELATIONSHIP_09_WITH_INCLUDE = f"{RELATED_DIRECTORY}verify_relationship_9000000009_include.yaml" +RELATED__VERIFY_RELATIONSHIP_25 = f"{RELATED_DIRECTORY}verify_relationship_9000000025.yaml" +RELATED__VERIFY_RELATIONSHIP_25_WITH_INCLUDE = f"{RELATED_DIRECTORY}verify_relationship_9000000025_include.yaml" RELATED__EMPTY_RESPONSE = f"{RELATED_DIRECTORY}empty_response_9000000033.yaml" diff --git a/sandbox/api/get_consent_by_id.py b/sandbox/api/get_consent_by_id.py index 4a9c2124..ae4e24c1 100644 --- a/sandbox/api/get_consent_by_id.py +++ b/sandbox/api/get_consent_by_id.py @@ -31,9 +31,7 @@ def get_consent_by_id_response(identifier: str) -> Union[dict, tuple]: try: params = request.args.to_dict() if "_include" not in params and len(params) > 0: - return generate_response_from_example( - BAD_REQUEST_INCLUDE_PARAM_INVALID, 422 - ) + return generate_response_from_example(BAD_REQUEST_INCLUDE_PARAM_INVALID, 422) else: _include = request.args.getlist("_include") @@ -56,9 +54,7 @@ def get_consent_by_id_response(identifier: str) -> Union[dict, tuple]: elif identifier == "a0922245-1072-40c3-8f4e-a7490c10d365": return generate_response_from_example(INVALIDATED_RESOURCE, 404) else: - return generate_response_from_example( - GET_CONSENT_BY_ID__INVALID_ID_ERROR, 400 - ) + return generate_response_from_example(GET_CONSENT_BY_ID__INVALID_ID_ERROR, 400) except Exception: logger.exception("An error occurred while processing the request") diff --git a/sandbox/api/get_questionnaire_response.py b/sandbox/api/get_questionnaire_response.py index 8e2cda08..b5793674 100644 --- a/sandbox/api/get_questionnaire_response.py +++ b/sandbox/api/get_questionnaire_response.py @@ -24,19 +24,13 @@ def get_questionnaire_response_response(access_request_id: str) -> Union[dict, t """ try: if access_request_id == "156e1560-e532-4e2a-85ad-5aeff03dc43e": - return generate_response_from_example( - GET_QUESTIONNAIRE_RESPONSE__SUCCESS, 200 - ) + return generate_response_from_example(GET_QUESTIONNAIRE_RESPONSE__SUCCESS, 200) elif access_request_id == "INVALID": - return generate_response_from_example( - GET_QUESTIONNAIRE_RESPONSE__INVALID, 400 - ) + return generate_response_from_example(GET_QUESTIONNAIRE_RESPONSE__INVALID, 400) elif access_request_id == "" or access_request_id is None: return generate_response_from_example(METHOD_NOT_ALLOWED, 405) elif access_request_id == "60d09b82-f4bb-41f9-b41e-767999b4ac9b": - return generate_response_from_example( - GET_QUESTIONNAIRE_RESPONSE__NOT_FOUND, 404 - ) + return generate_response_from_example(GET_QUESTIONNAIRE_RESPONSE__NOT_FOUND, 404) else: raise ValueError("Invalid access request ID") except Exception: diff --git a/sandbox/api/patch_consent.py b/sandbox/api/patch_consent.py index b1770bbc..822c3d06 100644 --- a/sandbox/api/patch_consent.py +++ b/sandbox/api/patch_consent.py @@ -45,9 +45,7 @@ def patch_consent_response(id: str) -> Union[dict, tuple]: elif id == "849ea584-2318-471b-a24c-cee1b5ad0137": # Invalid patch format - return generate_response_from_example( - PATCH_CONSENT__INVALID_PATCH_FORMAT, 400 - ) + return generate_response_from_example(PATCH_CONSENT__INVALID_PATCH_FORMAT, 400) elif id == "01abb0c5-b1ac-499d-9655-9cd0b8d3588f": # Invalid path @@ -55,27 +53,19 @@ def patch_consent_response(id: str) -> Union[dict, tuple]: elif id == "78c35330-fa2f-4934-a5dd-fff847f38de5": # Invalid status code - return generate_response_from_example( - PATCH_CONSENT__INVALID_STATUS_CODE, 422 - ) + return generate_response_from_example(PATCH_CONSENT__INVALID_STATUS_CODE, 422) elif id == "51fb4df5-815a-45cd-8427-04d6558336b7": # Invalid status reason - return generate_response_from_example( - PATCH_CONSENT__INVALID_STATUS_REASON, 422 - ) + return generate_response_from_example(PATCH_CONSENT__INVALID_STATUS_REASON, 422) elif id == "7b7f47b8-96e5-43eb-b733-283bf1449f2c": # Invalid state transition - return generate_response_from_example( - PATCH_CONSENT__INVALID_STATE_TRANSITION, 422 - ) + return generate_response_from_example(PATCH_CONSENT__INVALID_STATE_TRANSITION, 422) else: # Resource not found - return generate_response_from_example( - PATCH_CONSENT__RESOURCE_NOT_FOUND, 404 - ) + return generate_response_from_example(PATCH_CONSENT__RESOURCE_NOT_FOUND, 404) except Exception: # Handle any general error diff --git a/sandbox/api/post_consent.py b/sandbox/api/post_consent.py index cd6f9681..cd15be78 100644 --- a/sandbox/api/post_consent.py +++ b/sandbox/api/post_consent.py @@ -11,9 +11,7 @@ ) from .utils import generate_response_from_example -CONSENT_APP_BASE_PATH = ( - "https://sandbox.api.service.nhs.uk/validated-relationships/FHIR/R4/Consent" -) +CONSENT_APP_BASE_PATH = "https://sandbox.api.service.nhs.uk/validated-relationships/FHIR/R4/Consent" basicConfig(level=INFO, format="%(asctime)s - %(message)s") logger = getLogger(__name__) @@ -34,23 +32,15 @@ def post_consent_response() -> Union[dict, tuple]: # Successful parent-child proxy creation # Successful adult-adult proxy creation if patient_identifier == "9000000009" or patient_identifier == "9000000017": - header = { - "location": f"{CONSENT_APP_BASE_PATH}/90b9863e-e33c-4895-a333-fd0ea0e23205" - } - response = generate_response_from_example( - POST_CONSENT__SUCCESS, 201, headers=header - ) + header = {"location": f"{CONSENT_APP_BASE_PATH}/90b9863e-e33c-4895-a333-fd0ea0e23205"} + response = generate_response_from_example(POST_CONSENT__SUCCESS, 201, headers=header) # Duplicate relationship elif patient_identifier == "9000000049": - response = generate_response_from_example( - POST_CONSENT__DUPLICATE_RELATIONSHIP_ERROR, 409 - ) + response = generate_response_from_example(POST_CONSENT__DUPLICATE_RELATIONSHIP_ERROR, 409) # Invalid performer NHS number elif patient_identifier == "9000000000": - response = generate_response_from_example( - POST_CONSENT__PERFORMER_IDENTIFIER_ERROR, 422 - ) + response = generate_response_from_example(POST_CONSENT__PERFORMER_IDENTIFIER_ERROR, 422) else: # Out of scope errors raise ValueError("Invalid Request") diff --git a/sandbox/api/post_questionnaire_response.py b/sandbox/api/post_questionnaire_response.py index 76c001fe..da5cfde1 100644 --- a/sandbox/api/post_questionnaire_response.py +++ b/sandbox/api/post_questionnaire_response.py @@ -10,7 +10,9 @@ ) from .utils import generate_response_from_example -QUESTIONNAIRE_RESPONSE_APP_BASE_PATH = "https://sandbox.api.service.nhs.uk/validated-relationships/FHIR/R4/QuestionnaireResponse" +QUESTIONNAIRE_RESPONSE_APP_BASE_PATH = ( + "https://sandbox.api.service.nhs.uk/validated-relationships/FHIR/R4/QuestionnaireResponse" +) basicConfig(level=INFO, format="%(asctime)s - %(message)s") logger = getLogger(__name__) @@ -30,17 +32,11 @@ def post_questionnaire_response_response() -> Union[dict, tuple]: # Successful questionnaire response if source_identifier in ["9000000009", "9000000017"]: - header = { - "location": f"{QUESTIONNAIRE_RESPONSE_APP_BASE_PATH}?ID=156e1560-e532-4e2a-85ad-5aeff03dc43e" - } - response = generate_response_from_example( - POST_QUESTIONNAIRE_RESPONSE__SUCCESS, 200, headers=header - ) + header = {"location": f"{QUESTIONNAIRE_RESPONSE_APP_BASE_PATH}?ID=156e1560-e532-4e2a-85ad-5aeff03dc43e"} + response = generate_response_from_example(POST_QUESTIONNAIRE_RESPONSE__SUCCESS, 200, headers=header) # Duplicate relationship elif source_identifier == "9000000049": - response = generate_response_from_example( - POST_QUESTIONNAIRE_RESPONSE__DUPLICATE_RELATIONSHIP_ERROR, 409 - ) + response = generate_response_from_example(POST_QUESTIONNAIRE_RESPONSE__DUPLICATE_RELATIONSHIP_ERROR, 409) else: # Out of scope errors raise ValueError("Invalid Request") diff --git a/sandbox/api/tests/test_get_consent.py b/sandbox/api/tests/test_get_consent.py index e20ca4f8..c027b4d9 100644 --- a/sandbox/api/tests/test_get_consent.py +++ b/sandbox/api/tests/test_get_consent.py @@ -40,9 +40,7 @@ def test_get_consent_returns_expected_responses__mocked_get_consent( # Act response = client.get(f"{CONSENT_API_ENDPOINT}?{request_args}") # Assert - mock_generate_response_from_example.assert_called_once_with( - response_file_name, status_code - ) + mock_generate_response_from_example.assert_called_once_with(response_file_name, status_code) assert response.status_code == status_code assert response.json == loads(mocked_response.get_data(as_text=True)) @@ -214,9 +212,7 @@ def test_get_consent_returns_expected_responses__mocked_utils( # Act response = client.get(f"{CONSENT_API_ENDPOINT}?{request_args}") # Assert - mock_generate_response_from_example.assert_called_once_with( - response_file_name, status_code - ) + mock_generate_response_from_example.assert_called_once_with(response_file_name, status_code) assert response.status_code == status_code assert response.json == loads(mocked_response.get_data(as_text=True)) @@ -231,10 +227,6 @@ def test_get_consent__500_internal_server_error( """Test Consent endpoint.""" mock_remove_system.side_effect = Exception("Test exception") # Act - client.get( - f"{CONSENT_API_ENDPOINT}?performer:identifier=9000000015&status=active&_include=Consent:performer" - ) + client.get(f"{CONSENT_API_ENDPOINT}?performer:identifier=9000000015&status=active&_include=Consent:performer") # Assert - mock_generate_response_from_example.assert_called_once_with( - "./api/examples/errors/internal-server-error.yaml", 500 - ) + mock_generate_response_from_example.assert_called_once_with("./api/examples/errors/internal-server-error.yaml", 500) diff --git a/sandbox/api/tests/test_get_consent_by_id.py b/sandbox/api/tests/test_get_consent_by_id.py index 4d377510..d7eb5907 100644 --- a/sandbox/api/tests/test_get_consent_by_id.py +++ b/sandbox/api/tests/test_get_consent_by_id.py @@ -56,9 +56,7 @@ def test_get_consent_by_id_returns_expected_responses__mocked_get_consent_by_id( response = client.get(f"{CONSENT_API_ENDPOINT}/{consent_id}?{include_params}") # import pdb; pdb.set_trace() # Assert - mock_generate_response_from_example.assert_called_once_with( - response_file_name, status_code - ) + mock_generate_response_from_example.assert_called_once_with(response_file_name, status_code) assert response.status_code == status_code assert response.json == loads(mocked_response.get_data(as_text=True)) @@ -135,9 +133,7 @@ def test_get_consent_by_id_returns_expected_responses__mocked_utils( response = client.get(f"{CONSENT_API_ENDPOINT}/{consent_id}?{include_params}") # import pdb; pdb.set_trace() # Assert - mock_generate_response_from_example.assert_called_once_with( - response_file_name, status_code - ) + mock_generate_response_from_example.assert_called_once_with(response_file_name, status_code) assert response.status_code == status_code assert response.json == loads(mocked_response.get_data(as_text=True)) @@ -154,6 +150,4 @@ def test_get_consent_by_id__500_internal_server_error( # Act client.get(f"{CONSENT_API_ENDPOINT}/74eed847-ca25-4e76-8cf2-f2c2d7842a7a") # Assert - mock_generate_response_from_example.assert_called_once_with( - "./api/examples/errors/internal-server-error.yaml", 500 - ) + mock_generate_response_from_example.assert_called_once_with("./api/examples/errors/internal-server-error.yaml", 500) diff --git a/sandbox/api/tests/test_get_questionnaire_response.py b/sandbox/api/tests/test_get_questionnaire_response.py index 551d0eb6..9269662d 100644 --- a/sandbox/api/tests/test_get_questionnaire_response.py +++ b/sandbox/api/tests/test_get_questionnaire_response.py @@ -50,9 +50,7 @@ def test_get_questionnaire_response_id_returns_expected_responses__mocked_utils( # Act response = client.get(f"{GET_QUESTIONNAIRE_RESPONSE_API_ENDPOINT}{path}") # Assert - mock_generate_response_from_example.assert_called_once_with( - response_file_name, status_code - ) + mock_generate_response_from_example.assert_called_once_with(response_file_name, status_code) assert response.status_code == status_code assert response.json == loads(mocked_response.get_data(as_text=True)) @@ -73,8 +71,6 @@ def test_get_questionnaire_response_without_path_params_return_405_errors( # Act response = client.get(f"{GET_QUESTIONNAIRE_RESPONSE_API_ENDPOINT}{path}") # Assert - mock_generate_response_from_example.assert_called_once_with( - "./api/examples/errors/method-not-allowed.yaml", 405 - ) + mock_generate_response_from_example.assert_called_once_with("./api/examples/errors/method-not-allowed.yaml", 405) assert response.status_code == 405 assert response.json == loads(mocked_response.get_data(as_text=True)) diff --git a/sandbox/api/tests/test_get_related_person.py b/sandbox/api/tests/test_get_related_person.py index 082ba3fd..99f621f6 100644 --- a/sandbox/api/tests/test_get_related_person.py +++ b/sandbox/api/tests/test_get_related_person.py @@ -116,8 +116,6 @@ def test_related_person( # Act response = client.get(f"{RELATED_PERSON_API_ENDPOINT}?{request_args}") # Assert - mock_generate_response_from_example.assert_called_once_with( - response_file_name, status_code - ) + mock_generate_response_from_example.assert_called_once_with(response_file_name, status_code) assert response.status_code == status_code assert response.json == loads(mocked_response.get_data(as_text=True)) diff --git a/sandbox/api/tests/test_patch_consent.py b/sandbox/api/tests/test_patch_consent.py index 54b22f54..2db8a5c4 100644 --- a/sandbox/api/tests/test_patch_consent.py +++ b/sandbox/api/tests/test_patch_consent.py @@ -71,8 +71,6 @@ def test_patch_consent_on_request_returns_expected_response( json = [{"op": "replace", "path": "/status", "value": "inactive"}] response = client.patch(CONSENT_API_ENDPOINT + f"/{nhs_num}", json=json) # Assert - mock_generate_response_from_example.assert_called_once_with( - response_file_name, status_code - ) + mock_generate_response_from_example.assert_called_once_with(response_file_name, status_code) assert response.status_code == status_code assert response.json == loads(mocked_response.get_data(as_text=True)) diff --git a/sandbox/api/tests/test_post_consent.py b/sandbox/api/tests/test_post_consent.py index 4de19178..936cd596 100644 --- a/sandbox/api/tests/test_post_consent.py +++ b/sandbox/api/tests/test_post_consent.py @@ -55,13 +55,9 @@ def test_post_consent_when_valid_returns_expected_response( mock_generate_response_from_example.assert_called_once_with( response_file_name, status_code, - headers={ - "location": f"https://sandbox.api.service.nhs.uk/validated-relationships/FHIR/R4/Consent/{id}" - }, + headers={"location": f"https://sandbox.api.service.nhs.uk/validated-relationships/FHIR/R4/Consent/{id}"}, ) else: - mock_generate_response_from_example.assert_called_once_with( - response_file_name, status_code - ) + mock_generate_response_from_example.assert_called_once_with(response_file_name, status_code) assert response.status_code == status_code assert response.json == loads(mocked_response.get_data(as_text=True)) diff --git a/sandbox/api/tests/test_post_questionnaire_response.py b/sandbox/api/tests/test_post_questionnaire_response.py index 4c3f7f26..decf88c0 100644 --- a/sandbox/api/tests/test_post_questionnaire_response.py +++ b/sandbox/api/tests/test_post_questionnaire_response.py @@ -70,13 +70,9 @@ def test_post_questionnaire_response( mock_generate_response_from_example.assert_called_once_with( response_file_name, status_code, - headers={ - "location": f"{SANDBOX_API_URL}{QUESTIONNAIRE_RESPONSE_API_ENDPOINT}?ID={id}" - }, + headers={"location": f"{SANDBOX_API_URL}{QUESTIONNAIRE_RESPONSE_API_ENDPOINT}?ID={id}"}, ) else: - mock_generate_response_from_example.assert_called_once_with( - response_file_name, status_code - ) + mock_generate_response_from_example.assert_called_once_with(response_file_name, status_code) assert response.status_code == status_code assert response.json == loads(mocked_response.get_data(as_text=True)) diff --git a/sandbox/api/tests/test_utils.py b/sandbox/api/tests/test_utils.py index 08286d80..233befab 100644 --- a/sandbox/api/tests/test_utils.py +++ b/sandbox/api/tests/test_utils.py @@ -8,9 +8,7 @@ @patch(f"{FILE_PATH}.open") def test_get_response(mock_open: MagicMock) -> None: # Arrange - mock_open.return_value.__enter__.return_value.read.return_value = ( - '{"data": "mocked"}' - ) + mock_open.return_value.__enter__.return_value.read.return_value = '{"data": "mocked"}' file_name = "./api/responses/GET_RelatedPerson/identifier.json" # Act response = load_json_file(file_name) diff --git a/sandbox/api/utils.py b/sandbox/api/utils.py index 096b9bd0..563f5a9f 100644 --- a/sandbox/api/utils.py +++ b/sandbox/api/utils.py @@ -80,23 +80,18 @@ def check_for_get_consent_errors(request: Request) -> Optional[tuple]: patient_identifier = request.args.get("patient:identifier") if not performer_identifier and not patient_identifier: - return generate_response_from_example( - "./api/examples/GET_Consent/errors/missing-identifier.yaml", 400 - ) + return generate_response_from_example("./api/examples/GET_Consent/errors/missing-identifier.yaml", 400) for identifier in [performer_identifier, patient_identifier]: identifier_without_system = remove_system(identifier) if identifier and len(identifier_without_system) != 10: # invalid identifier - return generate_response_from_example( - "./api/examples/GET_Consent/errors/invalid-identifier.yaml", 422 - ) + return generate_response_from_example("./api/examples/GET_Consent/errors/invalid-identifier.yaml", 422) elif ( isinstance(identifier, str) and "|" in identifier - and "https://fhir.nhs.uk/Id/nhs-number" - == identifier.split("|", maxsplit=2)[0] + and "https://fhir.nhs.uk/Id/nhs-number" == identifier.split("|", maxsplit=2)[0] ): # invalid identifier system return generate_response_from_example( @@ -105,9 +100,7 @@ def check_for_get_consent_errors(request: Request) -> Optional[tuple]: ) elif identifier_without_system == "9000000012": # invalid status - return generate_response_from_example( - f"{GET_CONSENT_ERRORS}/gp-practice-not-found.yaml", 404 - ) + return generate_response_from_example(f"{GET_CONSENT_ERRORS}/gp-practice-not-found.yaml", 404) def check_for_empty(identifier: str, patient_identifier: str) -> Response: @@ -160,9 +153,7 @@ def check_for_validate( return generate_response_from_example(base_file, 200) -def check_for_list( - value: str, identifier: str, include: str, base_file: str, inc_file: str -) -> Response: +def check_for_list(value: str, identifier: str, include: str, base_file: str, inc_file: str) -> Response: """Check for a list relationship response for a given NHS number Args: @@ -213,9 +204,7 @@ def remove_system(identifier: Any) -> str: return "" -def generate_response_from_example( - example_path: str, status_code: int, headers: dict = None -) -> Response: +def generate_response_from_example(example_path: str, status_code: int, headers: dict = None) -> Response: """Converts an example file (yaml) to a response Args: @@ -270,11 +259,7 @@ def check_for_consent_include_params( else: logger.error("No consent:patient example provided") return generate_response_from_example(INTERNAL_SERVER_ERROR_EXAMPLE, 500) - elif ( - len(_include) == 2 - and CONSENT_PATIENT in _include - and CONSENT_PERFORMER in _include - ): + elif len(_include) == 2 and CONSENT_PATIENT in _include and CONSENT_PERFORMER in _include: return generate_response_from_example(include_both_response_yaml, 200) else: return generate_response_from_example(BAD_REQUEST_INCLUDE_PARAM_INVALID, 422) @@ -302,21 +287,13 @@ def check_for_consent_filtering( if status == [] or status is None: return generate_response_from_example(INVALIDATED_RESOURCE, 404) if status == ["active"]: - if ( - len(_include) == 2 - and CONSENT_PERFORMER in _include - and CONSENT_PERFORMER in _include - ): - return generate_response_from_example( - status_active_with_details_response_yaml, 200 - ) + if len(_include) == 2 and CONSENT_PERFORMER in _include and CONSENT_PERFORMER in _include: + return generate_response_from_example(status_active_with_details_response_yaml, 200) else: return generate_response_from_example(INVALIDATED_RESOURCE, 404) elif status == ["inactive"]: return generate_response_from_example(status_inactive_response_yaml, 200) elif len(status) == 2 and "active" in status and "proposed" in status: - return generate_response_from_example( - status_proposed_and_active_response_yaml, 200 - ) + return generate_response_from_example(status_proposed_and_active_response_yaml, 200) else: return generate_response_from_example(GET_CONSENT__STATUS_PARAM_INVALID, 422) From e98dd1902bf78b7e5d0bb2c51a9747546f75ae8d Mon Sep 17 00:00:00 2001 From: adamclarkson Date: Tue, 14 Oct 2025 15:39:53 +0100 Subject: [PATCH 8/9] NPA-5534: correct lint errors --- sandbox/api/get_questionnaire_response.py | 2 -- sandbox/api/tests/test_get_questionnaire_response.py | 2 -- 2 files changed, 4 deletions(-) diff --git a/sandbox/api/get_questionnaire_response.py b/sandbox/api/get_questionnaire_response.py index b5793674..84f4ccb6 100644 --- a/sandbox/api/get_questionnaire_response.py +++ b/sandbox/api/get_questionnaire_response.py @@ -1,8 +1,6 @@ from logging import INFO, basicConfig, getLogger from typing import Union -from flask import request - from .constants import ( GET_QUESTIONNAIRE_RESPONSE__INVALID, GET_QUESTIONNAIRE_RESPONSE__NOT_FOUND, diff --git a/sandbox/api/tests/test_get_questionnaire_response.py b/sandbox/api/tests/test_get_questionnaire_response.py index 9269662d..9e278b1f 100644 --- a/sandbox/api/tests/test_get_questionnaire_response.py +++ b/sandbox/api/tests/test_get_questionnaire_response.py @@ -3,8 +3,6 @@ from flask import Response from json import dumps, loads -from pycparser.plyparser import parameterized - GET_QUESTIONNAIRE_RESPONSE_API_ENDPOINT = "/FHIR/R4/QuestionnaireResponse" From 7e2eebdcf8d8d56465214e229e34372bfeffcf9c Mon Sep 17 00:00:00 2001 From: adamclarkson Date: Wed, 15 Oct 2025 13:25:44 +0100 Subject: [PATCH 9/9] NPA-5534: Updated naming of GET QR endpoint --- sandbox/api/app.py | 4 ++-- ...e_response.py => get_questionnaire_response_by_path_id.py} | 2 +- ...ponse.py => test_get_questionnaire_response_by_path_id.py} | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) rename sandbox/api/{get_questionnaire_response.py => get_questionnaire_response_by_path_id.py} (93%) rename sandbox/api/tests/{test_get_questionnaire_response.py => test_get_questionnaire_response_by_path_id.py} (96%) diff --git a/sandbox/api/app.py b/sandbox/api/app.py index 70afcb8b..6cc87571 100644 --- a/sandbox/api/app.py +++ b/sandbox/api/app.py @@ -5,7 +5,7 @@ from .get_consent import get_consent_response from .get_consent_by_id import get_consent_by_id_response -from .get_questionnaire_response import get_questionnaire_response_response +from .get_questionnaire_response_by_path_id import get_questionnaire_response_by_path_id_response from .get_related_person import get_related_person_response from .patch_consent import patch_consent_response from .post_consent import post_consent_response @@ -59,7 +59,7 @@ def get_questionnaire_response_id(identifier: str) -> Union[dict, tuple]: Returns: Union[dict, tuple]: Response for GET /QuestionnaireResponse """ - return get_questionnaire_response_response(identifier) + return get_questionnaire_response_by_path_id_response(identifier) @app.route(f"/{COMMON_PATH}/QuestionnaireResponse", methods=["POST"]) diff --git a/sandbox/api/get_questionnaire_response.py b/sandbox/api/get_questionnaire_response_by_path_id.py similarity index 93% rename from sandbox/api/get_questionnaire_response.py rename to sandbox/api/get_questionnaire_response_by_path_id.py index 84f4ccb6..56c06618 100644 --- a/sandbox/api/get_questionnaire_response.py +++ b/sandbox/api/get_questionnaire_response_by_path_id.py @@ -14,7 +14,7 @@ logger = getLogger(__name__) -def get_questionnaire_response_response(access_request_id: str) -> Union[dict, tuple]: +def get_questionnaire_response_by_path_id_response(access_request_id: str) -> Union[dict, tuple]: """Sandbox API for GET /QuestionnaireResponse/{id} Returns: diff --git a/sandbox/api/tests/test_get_questionnaire_response.py b/sandbox/api/tests/test_get_questionnaire_response_by_path_id.py similarity index 96% rename from sandbox/api/tests/test_get_questionnaire_response.py rename to sandbox/api/tests/test_get_questionnaire_response_by_path_id.py index 9e278b1f..605e7abf 100644 --- a/sandbox/api/tests/test_get_questionnaire_response.py +++ b/sandbox/api/tests/test_get_questionnaire_response_by_path_id.py @@ -31,7 +31,7 @@ ), ], ) -@patch("sandbox.api.get_questionnaire_response.generate_response_from_example") +@patch("sandbox.api.get_questionnaire_response_by_path_id.generate_response_from_example") def test_get_questionnaire_response_id_returns_expected_responses__mocked_utils( mock_generate_response_from_example: MagicMock, path: str,