Skip to content

Commit f354222

Browse files
authored
Merge pull request #183 from NHSDigital/dev/NPA-4689_GET_QuestionnaireResponse
NPA-4689 Refactor Sandbox Endpoints into Separate Files
2 parents 144e810 + 5d228e9 commit f354222

15 files changed

+700
-682
lines changed

sandbox/api/app.py

Lines changed: 21 additions & 155 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,18 @@
11
from logging import INFO, basicConfig, getLogger
22
from typing import Union
3-
from flask import Flask, request
4-
5-
from .constants import (
6-
INTERNAL_SERVER_ERROR_EXAMPLE,
7-
QUESTIONNAIRE_RESPONSE__SUCCESS,
8-
RELATED__LIST_RELATIONSHIP,
9-
RELATED__LIST_RELATIONSHIP_WITH_INCLUDE,
10-
RELATED__VERIFY_RELATIONSHIP_09,
11-
RELATED__VERIFY_RELATIONSHIP_09_WITH_INCLUDE,
12-
RELATED__VERIFY_RELATIONSHIP_25,
13-
RELATED__VERIFY_RELATIONSHIP_25_WITH_INCLUDE,
14-
POST_CONSENT__SUCCESS,
15-
POST_CONSENT__DUPLICATE_RELATIONSHIP_ERROR,
16-
POST_CONSENT__PERFORMER_IDENTIFIER_ERROR,
17-
PATCH_CONSENT__SUCCESS,
18-
PATCH_CONSENT__INVALID_PATCH_FORMAT,
19-
PATCH_CONSENT__INVALID_PATH,
20-
PATCH_CONSENT__INVALID_STATUS_CODE,
21-
PATCH_CONSENT__RESOURCE_NOT_FOUND,
22-
PATCH_CONSENT__INVALID_STATE_TRANSITION,
23-
)
3+
4+
from flask import Flask
5+
246
from .get_consent import get_consent_response
25-
from .utils import (
26-
check_for_empty,
27-
check_for_list,
28-
check_for_related_person_errors,
29-
check_for_validate,
30-
generate_response_from_example,
31-
remove_system,
32-
)
7+
from .get_related_person import get_related_person_response
8+
from .patch_consent import patch_consent_response
9+
from .post_consent import post_consent_response
10+
from .post_questionnaire_response import post_questionnaire_response_response
3311

3412
app = Flask(__name__)
3513
basicConfig(level=INFO, format="%(asctime)s - %(message)s")
3614
logger = getLogger(__name__)
37-
APP_BASE_PATH = "https://sandbox.api.service.nhs.uk/validated-relationships/FHIR/R4/Consent"
15+
3816
COMMON_PATH = "FHIR/R4"
3917

4018

@@ -56,54 +34,7 @@ def get_related_persons() -> Union[dict, tuple]:
5634
Returns:
5735
Union[dict, tuple]: Response for GET /RelatedPerson
5836
"""
59-
60-
try:
61-
# Check Headers
62-
if errors := check_for_related_person_errors(request):
63-
return errors
64-
65-
identifier = remove_system(request.args.get("identifier"))
66-
patient_identifier = remove_system(request.args.get("patient:identifier"))
67-
include = request.args.get("_include")
68-
69-
if empty := check_for_empty(identifier, patient_identifier):
70-
return empty
71-
72-
# Successful request, select response
73-
if zero_nine := check_for_validate(
74-
"9000000009",
75-
identifier,
76-
patient_identifier,
77-
include,
78-
RELATED__VERIFY_RELATIONSHIP_09,
79-
RELATED__VERIFY_RELATIONSHIP_09_WITH_INCLUDE,
80-
):
81-
return zero_nine
82-
83-
if two_five := check_for_validate(
84-
"9000000025",
85-
identifier,
86-
patient_identifier,
87-
include,
88-
RELATED__VERIFY_RELATIONSHIP_25,
89-
RELATED__VERIFY_RELATIONSHIP_25_WITH_INCLUDE,
90-
):
91-
return two_five
92-
93-
if one_seven := check_for_list(
94-
"9000000017",
95-
identifier,
96-
include,
97-
RELATED__LIST_RELATIONSHIP,
98-
RELATED__LIST_RELATIONSHIP_WITH_INCLUDE,
99-
):
100-
return one_seven
101-
102-
raise ValueError("Invalid request")
103-
104-
except Exception:
105-
logger.exception("GET related person failed")
106-
return generate_response_from_example(INTERNAL_SERVER_ERROR_EXAMPLE, 500)
37+
return get_related_person_response()
10738

10839

10940
@app.route(f"/{COMMON_PATH}/QuestionnaireResponse", methods=["POST"])
@@ -113,12 +44,7 @@ def post_questionnaire_response() -> Union[dict, tuple]:
11344
Returns:
11445
Union[dict, tuple]: Response for POST /QuestionnaireResponse
11546
"""
116-
117-
try:
118-
return generate_response_from_example(QUESTIONNAIRE_RESPONSE__SUCCESS, 200)
119-
except Exception:
120-
logger.exception("POST questionnaire response failed")
121-
return generate_response_from_example(INTERNAL_SERVER_ERROR_EXAMPLE, 500)
47+
return post_questionnaire_response_response()
12248

12349

12450
@app.route(f"/{COMMON_PATH}/Consent", methods=["GET"])
@@ -138,77 +64,17 @@ def post_consent() -> Union[dict, tuple]:
13864
Returns:
13965
Union[dict, tuple]: Response for POST /Consent
14066
"""
141-
try:
142-
logger.debug("Received request to POST consent")
143-
# Validate body - beyond the scope of sandbox - assume body is valid for scenario
144-
json = request.get_json()
145-
patient_identifier = json["performer"][0]["identifier"]["value"]
146-
response = None
147-
148-
# Successful parent-child proxy creation
149-
# Successful adult-adult proxy creation
150-
if patient_identifier == "9000000009" or patient_identifier == "9000000017":
151-
header = {"location": f"{APP_BASE_PATH}/{patient_identifier}"}
152-
response = generate_response_from_example(POST_CONSENT__SUCCESS, 201, headers=header)
153-
154-
# Duplicate relationship
155-
elif patient_identifier == "9000000049":
156-
response = generate_response_from_example(POST_CONSENT__DUPLICATE_RELATIONSHIP_ERROR, 409)
157-
# Invalid performer NHS number
158-
elif patient_identifier == "9000000000":
159-
response = generate_response_from_example(POST_CONSENT__PERFORMER_IDENTIFIER_ERROR, 422)
160-
else:
161-
# Out of scope errors
162-
raise ValueError("Invalid Request")
163-
164-
return response
165-
166-
except Exception:
167-
# Handle any general error
168-
logger.exception("POST Consent failed")
169-
return generate_response_from_example(INTERNAL_SERVER_ERROR_EXAMPLE, 500)
67+
return post_consent_response()
17068

17169

17270
@app.route(f"/{COMMON_PATH}/Consent/<identifier>", methods=["PATCH"])
173-
def patch_consent(identifier) -> Union[dict, tuple]:
174-
try:
175-
logger.debug("Received request to PATCH consent")
176-
# Validate body - validation is beyond the scope of the sandbox.
177-
# Assume all requests are valid
178-
179-
if identifier == "c6f48e4d":
180-
# Successful status update
181-
return generate_response_from_example(PATCH_CONSENT__SUCCESS, 200)
182-
183-
elif identifier == "0c56a594":
184-
# Successful end date for a role
185-
return generate_response_from_example(PATCH_CONSENT__SUCCESS, 200)
186-
187-
elif identifier == "b02ea26c":
188-
# Multiple valid changes
189-
return generate_response_from_example(PATCH_CONSENT__SUCCESS, 200)
190-
191-
elif identifier == "3a2679eb":
192-
# Invalid patch format
193-
return generate_response_from_example(PATCH_CONSENT__INVALID_PATCH_FORMAT, 400)
194-
195-
elif identifier == "94df7c8f":
196-
# Invalid path
197-
return generate_response_from_example(PATCH_CONSENT__INVALID_PATH, 400)
198-
199-
elif identifier == "2a7b736d":
200-
# Invalid status code
201-
return generate_response_from_example(PATCH_CONSENT__INVALID_STATUS_CODE, 422)
202-
203-
elif identifier == "6fb4361b":
204-
# Invalid state transition
205-
return generate_response_from_example(PATCH_CONSENT__INVALID_STATE_TRANSITION, 422)
206-
207-
else:
208-
# Resource not found
209-
return generate_response_from_example(PATCH_CONSENT__RESOURCE_NOT_FOUND, 404)
210-
211-
except Exception:
212-
# Handle any general error
213-
logger.exception("PATCH Consent failed")
214-
return generate_response_from_example(INTERNAL_SERVER_ERROR_EXAMPLE, 500)
71+
def patch_consent(identifier: str) -> Union[dict, tuple]:
72+
"""Sandbox API for PATCH /Consent
73+
74+
Args:
75+
identifier (str): Consent identifier to be patched
76+
77+
Returns:
78+
Union[dict, tuple]: Response for PATCH /Consent
79+
"""
80+
return patch_consent_response(identifier)

sandbox/api/get_consent.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44
from flask import request
55

66
from .constants import (
7-
INTERNAL_SERVER_ERROR_EXAMPLE,
8-
INVALIDATED_RESOURCE,
97
GET_CONSENT__FILTERED_RELATIONSHIPS_STATUS_ACTIVE,
108
GET_CONSENT__FILTERED_RELATIONSHIPS_STATUS_INACTIVE,
119
GET_CONSENT__FILTERED_RELATIONSHIPS_STATUS_PROPOSED_ACTIVE,
@@ -18,9 +16,11 @@
1816
GET_CONSENT__SINGLE_CONSENTING_ADULT_RELATIONSHIP_INCLUDE_BOTH,
1917
GET_CONSENT__SINGLE_MOTHER_CHILD_RELATIONSHIP,
2018
GET_CONSENT__SINGLE_MOTHER_CHILD_RELATIONSHIP_INCLUDE_BOTH,
19+
INTERNAL_SERVER_ERROR_EXAMPLE,
20+
INVALIDATED_RESOURCE,
2121
)
2222
from .utils import (
23-
check_for_consent_errors,
23+
check_for_get_consent_errors,
2424
check_for_consent_filtering,
2525
check_for_consent_include_params,
2626
generate_response_from_example,
@@ -39,7 +39,7 @@ def get_consent_response() -> Union[dict, tuple]:
3939
"""
4040
try:
4141
# Check Headers
42-
if errors := check_for_consent_errors(request):
42+
if errors := check_for_get_consent_errors(request):
4343
return errors
4444

4545
performer_identifier = remove_system(request.args.get("performer:identifier"))

sandbox/api/get_related_person.py

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
from logging import INFO, basicConfig, getLogger
2+
from typing import Union
3+
4+
from flask import request
5+
6+
from .constants import (
7+
INTERNAL_SERVER_ERROR_EXAMPLE,
8+
RELATED__LIST_RELATIONSHIP,
9+
RELATED__LIST_RELATIONSHIP_WITH_INCLUDE,
10+
RELATED__VERIFY_RELATIONSHIP_09,
11+
RELATED__VERIFY_RELATIONSHIP_09_WITH_INCLUDE,
12+
RELATED__VERIFY_RELATIONSHIP_25,
13+
RELATED__VERIFY_RELATIONSHIP_25_WITH_INCLUDE,
14+
)
15+
from .utils import (
16+
check_for_empty,
17+
check_for_get_related_person_errors,
18+
check_for_list,
19+
check_for_validate,
20+
generate_response_from_example,
21+
remove_system,
22+
)
23+
24+
basicConfig(level=INFO, format="%(asctime)s - %(message)s")
25+
logger = getLogger(__name__)
26+
27+
28+
def get_related_person_response() -> Union[dict, tuple]:
29+
"""Sandbox API for GET /RelatedPerson
30+
31+
Returns:
32+
Union[dict, tuple]: Response for GET /RelatedPerson
33+
"""
34+
try:
35+
# Check Headers
36+
if errors := check_for_get_related_person_errors(request):
37+
return errors
38+
39+
identifier = remove_system(request.args.get("identifier"))
40+
patient_identifier = remove_system(request.args.get("patient:identifier"))
41+
include = request.args.get("_include")
42+
43+
if empty := check_for_empty(identifier, patient_identifier):
44+
return empty
45+
46+
# Successful request, select response
47+
if zero_nine := check_for_validate(
48+
"9000000009",
49+
identifier,
50+
patient_identifier,
51+
include,
52+
RELATED__VERIFY_RELATIONSHIP_09,
53+
RELATED__VERIFY_RELATIONSHIP_09_WITH_INCLUDE,
54+
):
55+
return zero_nine
56+
57+
if two_five := check_for_validate(
58+
"9000000025",
59+
identifier,
60+
patient_identifier,
61+
include,
62+
RELATED__VERIFY_RELATIONSHIP_25,
63+
RELATED__VERIFY_RELATIONSHIP_25_WITH_INCLUDE,
64+
):
65+
return two_five
66+
67+
if one_seven := check_for_list(
68+
"9000000017",
69+
identifier,
70+
include,
71+
RELATED__LIST_RELATIONSHIP,
72+
RELATED__LIST_RELATIONSHIP_WITH_INCLUDE,
73+
):
74+
return one_seven
75+
76+
raise ValueError("Invalid request")
77+
78+
except Exception:
79+
logger.exception("GET related person failed")
80+
return generate_response_from_example(INTERNAL_SERVER_ERROR_EXAMPLE, 500)

sandbox/api/patch_consent.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
from logging import INFO, basicConfig, getLogger
2+
from typing import Union
3+
4+
from .constants import (
5+
INTERNAL_SERVER_ERROR_EXAMPLE,
6+
PATCH_CONSENT__INVALID_PATCH_FORMAT,
7+
PATCH_CONSENT__INVALID_PATH,
8+
PATCH_CONSENT__INVALID_STATE_TRANSITION,
9+
PATCH_CONSENT__INVALID_STATUS_CODE,
10+
PATCH_CONSENT__RESOURCE_NOT_FOUND,
11+
PATCH_CONSENT__SUCCESS,
12+
)
13+
from .utils import generate_response_from_example
14+
15+
basicConfig(level=INFO, format="%(asctime)s - %(message)s")
16+
logger = getLogger(__name__)
17+
18+
19+
def patch_consent_response(identifier: str) -> Union[dict, tuple]:
20+
"""Sandbox API for PATCH /Consent
21+
22+
Args:
23+
identifier (str): Consent identifier to be patched
24+
25+
Returns:
26+
Union[dict, tuple]: Response for PATCH /Consent
27+
"""
28+
try:
29+
logger.debug("Received request to PATCH consent")
30+
# Validate body - validation is beyond the scope of the sandbox.
31+
# Assume all requests are valid
32+
33+
if identifier == "c6f48e4d":
34+
# Successful status update
35+
return generate_response_from_example(PATCH_CONSENT__SUCCESS, 200)
36+
37+
elif identifier == "0c56a594":
38+
# Successful end date for a role
39+
return generate_response_from_example(PATCH_CONSENT__SUCCESS, 200)
40+
41+
elif identifier == "b02ea26c":
42+
# Multiple valid changes
43+
return generate_response_from_example(PATCH_CONSENT__SUCCESS, 200)
44+
45+
elif identifier == "3a2679eb":
46+
# Invalid patch format
47+
return generate_response_from_example(PATCH_CONSENT__INVALID_PATCH_FORMAT, 400)
48+
49+
elif identifier == "94df7c8f":
50+
# Invalid path
51+
return generate_response_from_example(PATCH_CONSENT__INVALID_PATH, 400)
52+
53+
elif identifier == "2a7b736d":
54+
# Invalid status code
55+
return generate_response_from_example(PATCH_CONSENT__INVALID_STATUS_CODE, 422)
56+
57+
elif identifier == "6fb4361b":
58+
# Invalid state transition
59+
return generate_response_from_example(PATCH_CONSENT__INVALID_STATE_TRANSITION, 422)
60+
61+
else:
62+
# Resource not found
63+
return generate_response_from_example(PATCH_CONSENT__RESOURCE_NOT_FOUND, 404)
64+
65+
except Exception:
66+
# Handle any general error
67+
logger.exception("PATCH Consent failed")
68+
return generate_response_from_example(INTERNAL_SERVER_ERROR_EXAMPLE, 500)

0 commit comments

Comments
 (0)