Skip to content

Commit ec888ee

Browse files
edhall-nhsAkol125
andauthored
VED-935: fix url response for empty identifier search bundle (#1010)
* Update empty identifier search bundle url Also moved some common code that was only used in the api service layer to the relevant place. * Remove redundant check --------- Co-authored-by: Akinola Olutola <[email protected]>
1 parent 03e2d3d commit ec888ee

File tree

3 files changed

+57
-69
lines changed

3 files changed

+57
-69
lines changed

lambdas/backend/src/service/fhir_service.py

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import os
55
import urllib.parse
66
import uuid
7-
from typing import Optional, cast
7+
from typing import Any, Optional, cast
88
from uuid import uuid4
99

1010
from fhir.resources.R4B.bundle import (
@@ -36,7 +36,6 @@
3636
from common.models.utils.generic_utils import (
3737
get_contained_patient,
3838
get_occurrence_datetime,
39-
make_search_bundle,
4039
)
4140
from common.models.utils.validation_utils import (
4241
get_vaccine_type,
@@ -103,7 +102,7 @@ def get_immunization_by_identifier(
103102
resource, resource_metadata = self.immunization_repo.get_immunization_by_identifier(identifier)
104103

105104
if not resource:
106-
return make_search_bundle(resource, None, elements, identifier, base_url)
105+
return self.make_empty_identifier_search_bundle(base_url)
107106

108107
vaccination_type = get_vaccine_type(resource)
109108

@@ -113,7 +112,9 @@ def get_immunization_by_identifier(
113112
patient_full_url = f"urn:uuid:{str(uuid4())}"
114113
filtered_resource = Filter.search(resource, patient_full_url)
115114

116-
return make_search_bundle(filtered_resource, resource_metadata.resource_version, elements, identifier, base_url)
115+
return self.make_identifier_search_bundle(
116+
filtered_resource, resource_metadata.resource_version, elements, identifier, base_url
117+
)
117118

118119
def get_immunization_and_version_by_id(self, imms_id: str, supplier_system: str) -> tuple[Immunization, str]:
119120
"""
@@ -336,6 +337,55 @@ def is_valid_date_to(self, immunization: dict, date_to: Optional[datetime.date])
336337

337338
return occurrence_datetime.date() <= date_to
338339

340+
@staticmethod
341+
def make_identifier_search_bundle(
342+
resource: Optional[dict],
343+
version_id: Optional[int],
344+
elements: Optional[set[str]],
345+
identifier: Identifier,
346+
base_url: str,
347+
) -> FhirBundle:
348+
searched_url = f"{base_url}?identifier={identifier.system}|{identifier.value}" + (
349+
f"&_elements={','.join(sorted(elements))}" if elements else ""
350+
)
351+
352+
meta = {"versionId": version_id}
353+
354+
# Full Immunization payload to be returned if only the identifier parameter was provided and truncated when
355+
# _elements is used
356+
if elements is not None:
357+
resource_for_bundle: dict[str, Any] = {"resourceType": "Immunization"}
358+
if "id" in elements:
359+
resource_for_bundle["id"] = resource["id"]
360+
if "meta" in elements:
361+
resource_for_bundle["meta"] = meta
362+
363+
else:
364+
resource_for_bundle = copy.deepcopy(resource)
365+
resource_for_bundle["meta"] = meta
366+
367+
entry = BundleEntry.construct(
368+
fullUrl=f"{base_url}/{resource['id']}",
369+
resource=(
370+
Immunization.construct(**resource_for_bundle)
371+
if elements
372+
else Immunization.parse_obj(resource_for_bundle)
373+
),
374+
search=BundleEntrySearch.construct(mode="match") if not elements else None,
375+
)
376+
377+
return FhirBundle(
378+
type="searchset",
379+
link=[BundleLink(relation="self", url=searched_url)],
380+
entry=[entry],
381+
total=1,
382+
)
383+
384+
@staticmethod
385+
def make_empty_identifier_search_bundle(base_url: str) -> FhirBundle:
386+
no_results_url = f"{base_url}?identifier=None"
387+
return FhirBundle(entry=[], link=[BundleLink(relation="self", url=no_results_url)], type="searchset", total=0)
388+
339389
@staticmethod
340390
def process_patient_for_bundle(patient: dict):
341391
"""

lambdas/backend/tests/service/test_fhir_service.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -280,8 +280,7 @@ def test_get_immunization_by_identifier_returns_empty_search_when_not_found(self
280280
result.link[0],
281281
BundleLink.construct(
282282
relation="self",
283-
url="https://internal-dev.api.service.nhs.uk/immunisation-fhir-api/FHIR/R4/Immunization?identifier=some-"
284-
"system|some-value",
283+
url="https://internal-dev.api.service.nhs.uk/immunisation-fhir-api/FHIR/R4/Immunization?identifier=None",
285284
),
286285
)
287286
self.assertEqual(result.entry, [])

lambdas/shared/src/common/models/utils/generic_utils.py

Lines changed: 2 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,10 @@
11
"""Generic utilities"""
22

33
import base64
4-
import copy
54
import datetime
65
import urllib.parse
7-
from typing import Any, Literal, Optional
8-
9-
from fhir.resources.R4B.bundle import (
10-
Bundle as FhirBundle,
11-
)
12-
from fhir.resources.R4B.bundle import (
13-
BundleEntry,
14-
BundleEntrySearch,
15-
BundleLink,
16-
)
17-
from fhir.resources.R4B.identifier import Identifier
18-
from fhir.resources.R4B.immunization import Immunization
6+
from typing import Literal, Optional
7+
198
from stdnum.verhoeff import validate
209

2110
from common.models.constants import Constants
@@ -155,56 +144,6 @@ def create_diagnostics_error(value):
155144
return exp_error
156145

157146

158-
def make_empty_search_bundle(searched_url: str) -> FhirBundle:
159-
return FhirBundle(entry=[], link=[BundleLink(relation="self", url=searched_url)], type="searchset", total=0)
160-
161-
162-
# A lot of stuff in here is not very generic. Consider moving to relevant lambdas
163-
def make_search_bundle(
164-
resource: Optional[dict],
165-
version_id: Optional[int],
166-
elements: Optional[set[str]],
167-
identifier: Identifier,
168-
base_url: str,
169-
) -> FhirBundle:
170-
searched_url = f"{base_url}?identifier={identifier.system}|{identifier.value}" + (
171-
f"&_elements={','.join(sorted(elements))}" if elements else ""
172-
)
173-
174-
if not resource:
175-
return make_empty_search_bundle(searched_url)
176-
177-
meta = {"versionId": version_id}
178-
179-
# Full Immunization payload to be returned if only the identifier parameter was provided and truncated when
180-
# _elements is used
181-
if elements is not None:
182-
resource_for_bundle: dict[str, Any] = {"resourceType": "Immunization"}
183-
if "id" in elements:
184-
resource_for_bundle["id"] = resource["id"]
185-
if "meta" in elements:
186-
resource_for_bundle["meta"] = meta
187-
188-
else:
189-
resource_for_bundle = copy.deepcopy(resource)
190-
resource_for_bundle["meta"] = meta
191-
192-
entry = BundleEntry.construct(
193-
fullUrl=f"{base_url}/{resource['id']}",
194-
resource=(
195-
Immunization.construct(**resource_for_bundle) if elements else Immunization.parse_obj(resource_for_bundle)
196-
),
197-
search=BundleEntrySearch.construct(mode="match") if not elements else None,
198-
)
199-
200-
return FhirBundle(
201-
type="searchset",
202-
link=[BundleLink(relation="self", url=searched_url)],
203-
entry=[entry],
204-
total=1,
205-
)
206-
207-
208147
def check_keys_in_sources(event, not_required_keys):
209148
# Decode and parse the body, assuming it is JSON and base64-encoded
210149
def decode_and_parse_body(encoded_body):

0 commit comments

Comments
 (0)