Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,6 @@ https://nhsd-jira.digital.nhs.uk/browse/NPA-XXXX
- [ ] Commit messages follow the template: `NPA-XXXX: <short-description>`
- [ ] All acceptance criteria from the Jira ticket are addressed
- [ ] Automated tests (unit/integration/API/infrastructure etc. tests) are added or updated
- [ ] The [traceability matrix](https://nhsd-confluence.digital.nhs.uk/display/NPA/Traceability+matrix) is updated
with
new tests or requirements
- [ ] Assignees and appropriate labels (e.g. `terraform`, `documentation`) are added

---
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ env
.dir-locals.el
*.pyc

openapitools.json

sandbox/output.json
sandbox/pytest_html_report.html
sandbox/archive/
Expand Down

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions sandbox/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ Please note all commands are meant to be run from this directory `/sandbox`

To run the API with hot reloading use `make start-dev`

### Updating examples

The examples held in `./api/examples/` are copied at sandbox startup from `../specification/examples/`. See [Makefile](./Makefile) `start` & `start-dev`.

### Testing

#### Unit Tests
Expand Down
4 changes: 2 additions & 2 deletions sandbox/api/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,8 @@
# 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_reference_code.yaml"
GET_QUESTIONNAIRE_RESPONSE__MISSING = f"{GET_QUESTIONNAIRE_RESPONSE_DIRECTORY}errors/missing_reference_code.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"
)
Expand Down
12 changes: 6 additions & 6 deletions sandbox/api/get_questionnaire_response.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,17 @@ def get_questionnaire_response_response() -> Union[dict, tuple]:
Union[dict, tuple]: Response for GET /QuestionnaireResponse
"""
try:
reference_code = request.args.get("referenceCode")
if reference_code == "19318ZGLAB":
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 reference_code == "INVALID":
elif access_request_id == "INVALID":
return generate_response_from_example(GET_QUESTIONNAIRE_RESPONSE__INVALID, 400)
elif reference_code == "" or reference_code is None:
elif access_request_id == "" or access_request_id is None:
return generate_response_from_example(GET_QUESTIONNAIRE_RESPONSE__MISSING, 400)
elif reference_code == "ABC123XY":
elif access_request_id == "60d09b82-f4bb-41f9-b41e-767999b4ac9b":
return generate_response_from_example(GET_QUESTIONNAIRE_RESPONSE__NOT_FOUND, 404)
else:
raise ValueError("Invalid reference code")
raise ValueError("Invalid access request ID")
except Exception:
logger.exception("GET questionnaire response failed")
return generate_response_from_example(INTERNAL_SERVER_ERROR_EXAMPLE, 500)
6 changes: 5 additions & 1 deletion sandbox/api/post_questionnaire_response.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +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"
)
basicConfig(level=INFO, format="%(asctime)s - %(message)s")
logger = getLogger(__name__)

Expand All @@ -29,7 +32,8 @@ def post_questionnaire_response_response() -> Union[dict, tuple]:

# Successful questionnaire response
if source_identifier in ["9000000009", "9000000017"]:
response = generate_response_from_example(POST_QUESTIONNAIRE_RESPONSE__SUCCESS, 200)
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)
Expand Down
16 changes: 8 additions & 8 deletions sandbox/api/tests/test_get_questionnaire_response.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,34 +10,34 @@
("request_args", "response_file_name", "status_code"),
[
(
"referenceCode=19318ZGLAB",
"ID=156e1560-e532-4e2a-85ad-5aeff03dc43e",
"./api/examples/GET_QuestionnaireResponse/success.yaml",
200,
),
(
"referenceCode=INVALID",
"./api/examples/GET_QuestionnaireResponse/errors/invalid_reference_code.yaml",
"ID=INVALID",
"./api/examples/GET_QuestionnaireResponse/errors/invalid_access_request_id.yaml",
400,
),
(
"referenceCode=",
"./api/examples/GET_QuestionnaireResponse/errors/missing_reference_code.yaml",
"ID=",
"./api/examples/GET_QuestionnaireResponse/errors/missing_access_request_id.yaml",
400,
),
(
"referenceCode=ABC123XY",
"ID=60d09b82-f4bb-41f9-b41e-767999b4ac9b",
"./api/examples/GET_QuestionnaireResponse/errors/questionnaire_response_not_found.yaml",
404,
),
(
"referenceCode=INVALID_CODE",
"ID=INVALID_CODE",
"./api/examples/errors/internal-server-error.yaml",
500,
),
],
)
@patch("sandbox.api.get_questionnaire_response.generate_response_from_example")
def test_get_consent_returns_expected_responses__mocked_utils(
def test_get_questionnaire_response_returns_expected_responses__mocked_utils(
mock_generate_response_from_example: MagicMock,
request_args: str,
response_file_name: str,
Expand Down
17 changes: 15 additions & 2 deletions sandbox/api/tests/test_post_questionnaire_response.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,38 +10,44 @@
INTERNAL_SERVER_ERROR_EXAMPLE,
)

SANDBOX_API_URL = "https://sandbox.api.service.nhs.uk/validated-relationships"
QUESTIONNAIRE_RESPONSE_API_ENDPOINT = "/FHIR/R4/QuestionnaireResponse"


@pytest.mark.parametrize(
("nhs_num", "response_file_name", "status_code"),
("nhs_num", "response_file_name", "status_code", "id"),
[
(
"9000000009",
POST_QUESTIONNAIRE_RESPONSE__SUCCESS,
200,
"156e1560-e532-4e2a-85ad-5aeff03dc43e",
),
(
"9000000017",
POST_QUESTIONNAIRE_RESPONSE__SUCCESS,
200,
"156e1560-e532-4e2a-85ad-5aeff03dc43e",
),
(
"9000000049",
POST_QUESTIONNAIRE_RESPONSE__DUPLICATE_RELATIONSHIP_ERROR,
409,
None,
),
(
"INVALID_NHS_NUMBER",
INTERNAL_SERVER_ERROR_EXAMPLE,
500,
None,
),
],
)
@patch("sandbox.api.post_questionnaire_response.generate_response_from_example")
def test_post_questionnaire_response(
mock_generate_response_from_example: MagicMock,
nhs_num: str,
id: str,
response_file_name: str,
status_code: int,
client: object,
Expand All @@ -57,6 +63,13 @@ def test_post_questionnaire_response(
# Act
response = client.post(QUESTIONNAIRE_RESPONSE_API_ENDPOINT, json=json)
# Assert
mock_generate_response_from_example.assert_called_once_with(response_file_name, status_code)
if id is not None:
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}"},
)
else:
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))
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
InvalidAccessRequestID:
summary: Invalid access request ID
description: The provided access request ID is invalid in format.
value:
resourceType: "OperationOutcome"
issue:
- severity: "error"
code: "invalid"
details:
coding:
- system: "https://fhir.nhs.uk/STU3/CodeSystem/Spine-ErrorOrWarningCode-1"
code: "INVALID_IDENTIFIER_VALUE"
display: "Invalid identifier value"
diagnostics: "The specified access request ID is invalid. Access request IDs must be a valid UUID."

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
MissingAccessRequestID:
summary: Missing access request ID
description: No access request ID was provided in the request.
value:
resourceType: "OperationOutcome"
issue:
- severity: "error"
code: "required"
details:
coding:
- system: "https://fhir.nhs.uk/STU3/CodeSystem/Spine-ErrorOrWarningCode-1"
code: "BAD_REQUEST"
display: "Bad request"
diagnostics: "The access request ID parameter is required but was not provided."

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
QuestionnaireResponseNotFound:
summary: Questionnaire response not found
description: The Questionnaire response could not be found using the provided reference code.
description: The Questionnaire response could not be found using the provided access request ID.
value:
resourceType: "OperationOutcome"
issue:
- severity: "error"
code: "not-found"
details:
coding:
- system: "https://fhir.nhs.uk/CodeSystem/Spine-ErrorOrWarningCode"
- system: "https://fhir.nhs.uk/STU3/CodeSystem/Spine-ErrorOrWarningCode-1"
code: "QUESTIONNAIRE_RESPONSE_NOT_FOUND"
display: "Questionnaire response not found"
diagnostics: "The Questionnaire response could not be found using the provided reference code."
diagnostics: "The Questionnaire response could not be found using the provided access request ID."
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ GetQuestionnaireResponseSuccess:
resourceType: QuestionnaireResponse
status: "completed"
authored: "2024-07-15T09:43:03.280Z"
id: "156e1560-e532-4e2a-85ad-5aeff03dc43e"
identifier:
value: "19318ZGLAB"
source:
type: "RelatedPerson"
identifier:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ PostQuestionnaireResponseSuccess:
details:
coding:
- code: "19318ZGLAB"
display: "19318ZGLAB"
display: "19318ZGLAB"
Loading