Skip to content

Commit 3de5bba

Browse files
authored
VED-967 Fix internal-qa url (#1065)
1 parent 958d699 commit 3de5bba

File tree

6 files changed

+110
-83
lines changed

6 files changed

+110
-83
lines changed

lambdas/backend/src/controller/fhir_controller.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
from service.fhir_service import FhirService, get_service_url
3737

3838
IMMUNIZATION_ENV = os.getenv("IMMUNIZATION_ENV")
39+
IMMUNIZATION_BASE_PATH = os.getenv("IMMUNIZATION_BASE_PATH")
3940

4041

4142
def make_controller(
@@ -51,7 +52,7 @@ def make_controller(
5152

5253
class FhirController:
5354
_IMMUNIZATION_ID_PATTERN = r"^[A-Za-z0-9\-.]{1,64}$"
54-
_API_SERVICE_URL = get_service_url()
55+
_API_SERVICE_URL = get_service_url(IMMUNIZATION_ENV, IMMUNIZATION_BASE_PATH)
5556

5657
def __init__(
5758
self,
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
"""Constants for the fhir_service layer"""
2+
3+
DEFAULT_BASE_PATH = "immunisation-fhir-api/FHIR/R4"
4+
PR_ENV_PREFIX = "pr-"

lambdas/backend/src/service/fhir_service.py

Lines changed: 12 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
import datetime
33
import logging
44
import os
5-
import urllib.parse
65
import uuid
76
from typing import Any, Optional, cast
87
from uuid import uuid4
@@ -43,11 +42,10 @@
4342
validate_identifiers_match,
4443
validate_resource_versions_match,
4544
)
46-
from controller.constants import IMMUNIZATION_TARGET_LEGACY_KEY_NAME, ImmunizationSearchParameterName
47-
from controller.parameter_parser import PATIENT_IDENTIFIER_SYSTEM
4845
from filter import Filter
4946
from models.errors import UnauthorizedVaxError
5047
from repository.fhir_repository import ImmunizationRepository
48+
from service.search_url_helper import create_url_for_bundle_link, get_service_url
5149

5250
logging.basicConfig(level="INFO")
5351
logger = logging.getLogger()
@@ -59,24 +57,6 @@
5957
IMMUNIZATION_VALIDATOR = ImmunizationValidator()
6058

6159

62-
def get_service_url(
63-
service_env: str = IMMUNIZATION_ENV,
64-
service_base_path: str = IMMUNIZATION_BASE_PATH,
65-
) -> str:
66-
if not service_base_path:
67-
service_base_path = "immunisation-fhir-api/FHIR/R4"
68-
69-
non_prod = ["internal-dev", "int", "sandbox"]
70-
if service_env in non_prod:
71-
subdomain = f"{service_env}."
72-
elif service_env == "prod":
73-
subdomain = ""
74-
else:
75-
subdomain = "internal-dev."
76-
77-
return f"https://{subdomain}api.service.nhs.uk/{service_base_path}"
78-
79-
8060
class FhirService:
8161
_DATA_MISSING_DATE_TIME_ERROR_MSG = (
8262
"Data quality issue - immunisation with ID %s was found containing no occurrenceDateTime"
@@ -98,7 +78,7 @@ def get_immunization_by_identifier(
9878
"""
9979
Get an Immunization by its ID. Returns a FHIR Bundle containing the search results.
10080
"""
101-
base_url = f"{get_service_url()}/Immunization"
81+
base_url = f"{get_service_url(IMMUNIZATION_ENV, IMMUNIZATION_BASE_PATH)}/Immunization"
10282
resource, resource_metadata = self.immunization_repo.get_immunization_by_identifier(identifier)
10383

10484
if not resource:
@@ -251,7 +231,7 @@ def search_immunizations(
251231
BundleEntry(
252232
resource=Immunization.parse_obj(imms),
253233
search=BundleEntrySearch(mode="match"),
254-
fullUrl=f"{get_service_url()}/Immunization/{imms['id']}",
234+
fullUrl=f"{get_service_url(IMMUNIZATION_ENV, IMMUNIZATION_BASE_PATH)}/Immunization/{imms['id']}",
255235
)
256236
for imms in processed_resources
257237
]
@@ -288,7 +268,15 @@ def search_immunizations(
288268
link=[
289269
BundleLink(
290270
relation="self",
291-
url=self.create_url_for_bundle_link(permitted_vacc_types, nhs_number, date_from, date_to, include),
271+
url=create_url_for_bundle_link(
272+
permitted_vacc_types,
273+
nhs_number,
274+
date_from,
275+
date_to,
276+
include,
277+
IMMUNIZATION_ENV,
278+
IMMUNIZATION_BASE_PATH,
279+
),
292280
)
293281
],
294282
total=len(processed_resources),
@@ -408,29 +396,3 @@ def process_patient_for_bundle(patient: dict):
408396
new_patient["id"] = new_patient["identifier"][0].get("value")
409397

410398
return new_patient
411-
412-
@staticmethod
413-
def create_url_for_bundle_link(
414-
immunization_targets: set[str],
415-
patient_nhs_number: str,
416-
date_from: Optional[datetime.date],
417-
date_to: Optional[datetime.date],
418-
include: Optional[str],
419-
) -> str:
420-
"""Creates url for the searchset Bundle Link."""
421-
params = {
422-
# Temporarily maintaining this for backwards compatibility with imms history, but we should remove it
423-
IMMUNIZATION_TARGET_LEGACY_KEY_NAME: ",".join(immunization_targets),
424-
ImmunizationSearchParameterName.IMMUNIZATION_TARGET: ",".join(immunization_targets),
425-
ImmunizationSearchParameterName.PATIENT_IDENTIFIER: f"{PATIENT_IDENTIFIER_SYSTEM}|{patient_nhs_number}",
426-
}
427-
428-
if date_from:
429-
params[ImmunizationSearchParameterName.DATE_FROM] = date_from.isoformat()
430-
if date_to:
431-
params[ImmunizationSearchParameterName.DATE_TO] = date_to.isoformat()
432-
if include:
433-
params[ImmunizationSearchParameterName.INCLUDE] = include
434-
435-
query = urllib.parse.urlencode(params)
436-
return f"{get_service_url()}/Immunization?{query}"
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
"""Module containing helper functions for the constructions of Immunisation FHIR API search URLs"""
2+
3+
import datetime
4+
import urllib.parse
5+
from typing import Optional
6+
7+
from controller.constants import IMMUNIZATION_TARGET_LEGACY_KEY_NAME, ImmunizationSearchParameterName
8+
from controller.parameter_parser import PATIENT_IDENTIFIER_SYSTEM
9+
from service.constants import DEFAULT_BASE_PATH, PR_ENV_PREFIX
10+
11+
12+
def get_service_url(service_env: Optional[str], service_base_path: Optional[str]) -> str:
13+
"""Sets the service URL based on service parameters derived from env vars. PR environments use internal-dev while
14+
we also default to this environment. The only other exceptions are preprod which maps to the Apigee int environment
15+
and prod which does not have a subdomain."""
16+
if not service_base_path:
17+
service_base_path = DEFAULT_BASE_PATH
18+
19+
if service_env is None or is_pr_env(service_env):
20+
subdomain = "internal-dev."
21+
elif service_env == "preprod":
22+
subdomain = "int."
23+
elif service_env == "prod":
24+
subdomain = ""
25+
else:
26+
subdomain = f"{service_env}."
27+
28+
return f"https://{subdomain}api.service.nhs.uk/{service_base_path}"
29+
30+
31+
def is_pr_env(service_env: Optional[str]) -> bool:
32+
return service_env is not None and service_env.startswith(PR_ENV_PREFIX)
33+
34+
35+
def create_url_for_bundle_link(
36+
immunization_targets: set[str],
37+
patient_nhs_number: str,
38+
date_from: Optional[datetime.date],
39+
date_to: Optional[datetime.date],
40+
include: Optional[str],
41+
service_env: Optional[str],
42+
service_base_path: Optional[str],
43+
) -> str:
44+
"""Creates url for the searchset Bundle Link."""
45+
params = {
46+
# Temporarily maintaining this for backwards compatibility with imms history, but we should remove it
47+
IMMUNIZATION_TARGET_LEGACY_KEY_NAME: ",".join(immunization_targets),
48+
ImmunizationSearchParameterName.IMMUNIZATION_TARGET: ",".join(immunization_targets),
49+
ImmunizationSearchParameterName.PATIENT_IDENTIFIER: f"{PATIENT_IDENTIFIER_SYSTEM}|{patient_nhs_number}",
50+
}
51+
52+
if date_from:
53+
params[ImmunizationSearchParameterName.DATE_FROM] = date_from.isoformat()
54+
if date_to:
55+
params[ImmunizationSearchParameterName.DATE_TO] = date_to.isoformat()
56+
if include:
57+
params[ImmunizationSearchParameterName.INCLUDE] = include
58+
59+
query = urllib.parse.urlencode(params)
60+
return f"{get_service_url(service_env, service_base_path)}/Immunization?{query}"

lambdas/backend/tests/service/test_fhir_service.py

Lines changed: 3 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
from common.models.immunization_record_metadata import ImmunizationRecordMetadata
2323
from models.errors import UnauthorizedVaxError
2424
from repository.fhir_repository import ImmunizationRepository
25-
from service.fhir_service import FhirService, get_service_url
25+
from service.fhir_service import FhirService
2626
from test_common.testing_utils.generic_utils import load_json_data
2727
from test_common.testing_utils.immunization_utils import (
2828
VALID_NHS_NUMBER,
@@ -46,43 +46,14 @@ def setUp(self):
4646
self.mock_redis_getter = self.redis_getter_patcher.start()
4747
self.logger_info_patcher = patch("logging.Logger.info")
4848
self.mock_logger_info = self.logger_info_patcher.start()
49+
self.imms_env_patcher = patch("service.fhir_service.IMMUNIZATION_ENV", "internal-dev")
50+
self.imms_env_patcher.start()
4951

5052
def tearDown(self):
5153
super().tearDown()
5254
patch.stopall()
5355

5456

55-
class TestServiceUrl(unittest.TestCase):
56-
def setUp(self):
57-
self.logger_info_patcher = patch("logging.Logger.info")
58-
self.mock_logger_info = self.logger_info_patcher.start()
59-
60-
def tearDown(self):
61-
patch.stopall()
62-
63-
def test_get_service_url(self):
64-
"""it should create service url"""
65-
env = "int"
66-
base_path = "immunisation-fhir-api/FHIR/R4"
67-
url = get_service_url(env, base_path)
68-
self.assertEqual(url, f"https://{env}.api.service.nhs.uk/{base_path}")
69-
# default should be internal-dev
70-
env = "it-does-not-exist"
71-
base_path = "immunisation-fhir-api/FHIR/R4"
72-
url = get_service_url(env, base_path)
73-
self.assertEqual(url, f"https://internal-dev.api.service.nhs.uk/{base_path}")
74-
# prod should not have a subdomain
75-
env = "prod"
76-
base_path = "immunisation-fhir-api/FHIR/R4"
77-
url = get_service_url(env, base_path)
78-
self.assertEqual(url, f"https://api.service.nhs.uk/{base_path}")
79-
# any other env should fall back to internal-dev (like pr-xx or per-user)
80-
env = "pr-42"
81-
base_path = "immunisation-fhir-api/FHIR/R4"
82-
url = get_service_url(env, base_path)
83-
self.assertEqual(url, f"https://internal-dev.api.service.nhs.uk/{base_path}")
84-
85-
8657
class TestGetImmunization(TestFhirServiceBase):
8758
"""Tests for FhirService.get_immunization_by_id"""
8859

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
"""Tests for the search_url_helper file"""
2+
3+
import unittest
4+
5+
from service.search_url_helper import get_service_url
6+
7+
8+
class TestServiceUrl(unittest.TestCase):
9+
def test_get_service_url(self):
10+
"""it should create service url"""
11+
test_cases = [
12+
("pr-123", "https://internal-dev.api.service.nhs.uk/immunisation-fhir-api/FHIR/R4"),
13+
(None, "https://internal-dev.api.service.nhs.uk/immunisation-fhir-api/FHIR/R4"),
14+
("preprod", "https://int.api.service.nhs.uk/immunisation-fhir-api/FHIR/R4"),
15+
("prod", "https://api.service.nhs.uk/immunisation-fhir-api/FHIR/R4"),
16+
("ref", "https://ref.api.service.nhs.uk/immunisation-fhir-api/FHIR/R4"),
17+
("internal-dev", "https://internal-dev.api.service.nhs.uk/immunisation-fhir-api/FHIR/R4"),
18+
("internal-qa", "https://internal-qa.api.service.nhs.uk/immunisation-fhir-api/FHIR/R4"),
19+
]
20+
mock_base_path = "immunisation-fhir-api/FHIR/R4"
21+
22+
for mock_env, expected in test_cases:
23+
with self.subTest(mock_env=mock_env, expected=expected):
24+
self.assertEqual(get_service_url(mock_env, mock_base_path), expected)
25+
26+
def test_get_service_url_uses_default_path_when_not_provided(self):
27+
self.assertEqual(
28+
get_service_url(None, None), "https://internal-dev.api.service.nhs.uk/immunisation-fhir-api/FHIR/R4"
29+
)

0 commit comments

Comments
 (0)