From 8aa267aea00ef32418d48ebbd2d726d7e6c2e96d Mon Sep 17 00:00:00 2001 From: mcmcphillips Date: Tue, 16 Jul 2024 14:12:02 -0700 Subject: [PATCH] MAT-7348: Handle successive requests for valueSet Search endpoint --- .../service/FhirTerminologyService.java | 137 ++++++++++++------ .../FhirTerminologyServiceWebClient.java | 2 +- .../VsacFhirTerminologyControllerTest.java | 3 +- 3 files changed, 94 insertions(+), 48 deletions(-) diff --git a/src/main/java/gov/cms/madie/terminology/service/FhirTerminologyService.java b/src/main/java/gov/cms/madie/terminology/service/FhirTerminologyService.java index 73ab8f3..c6563a8 100644 --- a/src/main/java/gov/cms/madie/terminology/service/FhirTerminologyService.java +++ b/src/main/java/gov/cms/madie/terminology/service/FhirTerminologyService.java @@ -131,53 +131,98 @@ public ValueSetSearchResult searchValueSets(String apiKey, Map q .getEntry() .forEach( entry -> { - Resource resource = entry.getResource(); - ValueSet vs = (ValueSet) resource; - if (resource instanceof ValueSet) { - String oid = ""; - for (Identifier identifier : ((ValueSet) resource).getIdentifier()) { - if (identifier.getValue() != null && !identifier.getValue().isEmpty()) { - oid = identifier.getValue(); - } - } - ValueSetForSearch valueSet = - ValueSetForSearch.builder() - .title(vs.getTitle()) - .author( - Optional.ofNullable( - vs.getExtensionByUrl( - "http://hl7.org/fhir/StructureDefinition/valueset-author")) - .map(extension -> String.valueOf(extension.getValue())) - .orElse("")) - .name(vs.getName()) - .composedOf( - vs.getCompose().getInclude().stream() - .map(x -> x.getSystem()) - .collect(Collectors.joining(","))) - .effectiveDate( - String.valueOf( - vs.getExtensionByUrl( - "http://hl7.org/fhir/StructureDefinition/valueset-effectiveDate") - .getValue())) - .lastReviewDate( - String.valueOf( - vs.getExtensionByUrl( - "http://hl7.org/fhir/StructureDefinition/resource-lastReviewDate") - .getValue())) - .lastUpdated(vs.getMeta().getLastUpdated().toString()) - .url(vs.getUrl()) - .version(vs.getVersion()) - .status(vs.getStatus()) - .publisher(vs.getPublisher()) - .purpose(vs.getPurpose()) - .steward(vs.getPublisher()) - .oid(oid) - .build(); - valueSetList.add(valueSet); - } - log.info("valueSetList {}", valueSetList); + traverseValueSet(entry, valueSetList); }); - return ValueSetSearchResult.builder().valueSets(valueSetList).resultBundle(responseString).build(); + // if there's a next link we want to hit it, and append the results until we're out of results + var links = bundle.getLink(); + links.forEach( + (l) -> { + if (l.getRelation().equals("next")) { + recursiveRequestValueSets(valueSetList, apiKey, l.getUrl()); + } + }); + + return ValueSetSearchResult.builder() + .valueSets(valueSetList) + .resultBundle(responseString) + .build(); + } + + public void recursiveRequestValueSets( + List allValueSets, String apiKey, String uriString) { + String httpsString = uriString.replaceFirst("http", "https"); + log.info( + "uri we're going to hit is[{}]", + httpsString); // vsac gives us http, we want https or it fails + IParser parser = fhirContext.newJsonParser(); + String responseString = + fhirTerminologyServiceWebClient.fetchResourceFromVsac(httpsString, apiKey, "bundle"); + Bundle bundle = parser.parseResource(Bundle.class, responseString); + List valueSetListPage = new ArrayList<>(); + bundle + .getEntry() + .forEach( + entry -> { + traverseValueSet(entry, valueSetListPage); + }); + allValueSets.addAll(valueSetListPage); + var links = bundle.getLink(); + links.forEach( + (l) -> { + if (l.getRelation().equals("next")) { + recursiveRequestValueSets(allValueSets, apiKey, l.getUrl()); + } + }); + } + + private void traverseValueSet( + Bundle.BundleEntryComponent entry, List valueSetList) { + Resource resource = entry.getResource(); + ValueSet vs = (ValueSet) resource; + if (resource instanceof ValueSet) { + String oid = ""; + for (Identifier identifier : ((ValueSet) resource).getIdentifier()) { + if (identifier.getValue() != null && !identifier.getValue().isEmpty()) { + oid = identifier.getValue(); + } + } + ValueSetForSearch valueSet = + ValueSetForSearch.builder() + .title(vs.getTitle()) + .author( + Optional.ofNullable( + vs.getExtensionByUrl( + "http://hl7.org/fhir/StructureDefinition/valueset-author")) + .map(extension -> String.valueOf(extension.getValue())) + .orElse("")) + .name(vs.getName()) + .composedOf( + vs.getCompose().getInclude().stream() + .map(x -> x.getSystem()) + .collect(Collectors.joining(","))) + .effectiveDate( + Optional.ofNullable( + vs.getExtensionByUrl( + "http://hl7.org/fhir/StructureDefinition/valueset-effectiveDate")) + .map(extension -> String.valueOf(extension.getValue())) + .orElse("")) + .lastReviewDate( + Optional.ofNullable( + vs.getExtensionByUrl( + "http://hl7.org/fhir/StructureDefinition/resource-lastReviewDate")) + .map(extension -> String.valueOf(extension.getValue())) + .orElse("")) + .lastUpdated(vs.getMeta().getLastUpdated().toString()) + .url(vs.getUrl()) + .version(vs.getVersion()) + .status(vs.getStatus()) + .publisher(vs.getPublisher()) + .purpose(vs.getPurpose()) + .steward(vs.getPublisher()) + .oid(oid) + .build(); + valueSetList.add(valueSet); + } } public List getAllCodeSystems() { diff --git a/src/main/java/gov/cms/madie/terminology/webclient/FhirTerminologyServiceWebClient.java b/src/main/java/gov/cms/madie/terminology/webclient/FhirTerminologyServiceWebClient.java index 4e04c7d..2686101 100644 --- a/src/main/java/gov/cms/madie/terminology/webclient/FhirTerminologyServiceWebClient.java +++ b/src/main/java/gov/cms/madie/terminology/webclient/FhirTerminologyServiceWebClient.java @@ -122,7 +122,7 @@ public String getCodeResource(String code, CodeSystem codeSystem, String apiKey) return fetchResourceFromVsac(uri.toString(), apiKey, "Code"); } - private String fetchResourceFromVsac(String uri, String apiKey, String resourceType) { + public String fetchResourceFromVsac(String uri, String apiKey, String resourceType) { return fhirTerminologyWebClient .get() .uri(uri) diff --git a/src/test/java/gov/cms/madie/terminology/controller/VsacFhirTerminologyControllerTest.java b/src/test/java/gov/cms/madie/terminology/controller/VsacFhirTerminologyControllerTest.java index 58d8579..7a41569 100644 --- a/src/test/java/gov/cms/madie/terminology/controller/VsacFhirTerminologyControllerTest.java +++ b/src/test/java/gov/cms/madie/terminology/controller/VsacFhirTerminologyControllerTest.java @@ -285,7 +285,8 @@ void testSearchValueSets() { Principal principal = mock(Principal.class); when(principal.getName()).thenReturn(TEST_USER); when(vsacService.verifyUmlsAccess(anyString())).thenReturn(umlsUser); - when(fhirTerminologyService.searchValueSets(any(), any())).thenReturn(ValueSetSearchResult.builder().valueSets(mockValueSets).build()); + when(fhirTerminologyService.searchValueSets(any(), any())) + .thenReturn(ValueSetSearchResult.builder().valueSets(mockValueSets).build()); Map queryParams = new HashMap<>(); queryParams.put("param1", "value1"); queryParams.put("param2", "value2");