Skip to content

Commit

Permalink
AB2D-6276 / Research LOE for HttpGet to HttpPost request change (#416)
Browse files Browse the repository at this point in the history
* AB2D-6276 Research LOE for HttpGet to HttpPost request change
  • Loading branch information
smirnovaae authored Dec 12, 2024
1 parent 61100d0 commit 18a8852
Show file tree
Hide file tree
Showing 6 changed files with 81 additions and 54 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package gov.cms.ab2d.bfd.client;

import ca.uhn.fhir.rest.api.SearchStyleEnum;
import ca.uhn.fhir.rest.gclient.TokenClientParam;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
Expand Down Expand Up @@ -163,6 +164,7 @@ public IBaseBundle requestPartDEnrolleesFromServer(FhirVersion version, String c
.withAdditionalHeader(BFDClient.BFD_HDR_BULK_JOBID, getJobId())
.withAdditionalHeader(INCLUDE_IDENTIFIERS_HEADER, MBI_HEADER_VALUE)
.count(contractToBenePageSize)
.usingStyle(SearchStyleEnum.POST)
.returnBundle(version.getBundleClass())
.encodedJson()
.execute();
Expand Down Expand Up @@ -191,6 +193,7 @@ public IBaseBundle requestPartDEnrolleesFromServer(FhirVersion version, String c
.withAdditionalHeader(BFDClient.BFD_HDR_BULK_JOBID, getJobId())
.withAdditionalHeader(INCLUDE_IDENTIFIERS_HEADER, MBI_HEADER_VALUE)
.count(contractToBenePageSize)
.usingStyle(SearchStyleEnum.POST)
.returnBundle(version.getBundleClass())
.encodedJson()
.execute();
Expand Down
41 changes: 24 additions & 17 deletions ab2d-bfd/src/main/java/gov/cms/ab2d/bfd/client/BFDSearchImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.message.BasicNameValuePair;
import org.hl7.fhir.instance.model.api.IBaseBundle;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
Expand All @@ -17,6 +20,8 @@
import java.io.IOException;
import java.io.InputStream;
import java.time.OffsetDateTime;
import java.util.ArrayList;
import java.util.List;

@Component
@Slf4j
Expand Down Expand Up @@ -49,31 +54,33 @@ public BFDSearchImpl(HttpClient httpClient, Environment environment, BfdClientVe
@Override
public IBaseBundle searchEOB(long patientId, OffsetDateTime since, OffsetDateTime until, int pageSize, String bulkJobId, FhirVersion version, String contractNum) throws IOException {
String urlLocation = bfdClientVersions.getUrl(version);
StringBuilder url = new StringBuilder(urlLocation + "ExplanationOfBenefit?patient=" + patientId + "&excludeSAMHSA=true");

if (since != null) {
url.append("&_lastUpdated=ge").append(since);
}

if (until != null) {
url.append("&_lastUpdated=le").append(until);
}

if (pageSize > 0) {
url.append("&_count=").append(pageSize);
}

HttpGet request = new HttpGet(url.toString());
HttpPost request = new HttpPost(urlLocation + "ExplanationOfBenefit/_search");
// No active profiles means use JSON
if (environment.getActiveProfiles().length == 0) {
request.addHeader("Accept", "application/fhir+json;q=1.0, application/json+fhir;q=0.9");
}

request.addHeader(HttpHeaders.ACCEPT, "gzip");
request.addHeader(HttpHeaders.ACCEPT_CHARSET, "utf-8");
request.addHeader(BFDClient.BFD_HDR_BULK_CLIENTID, contractNum);
request.addHeader(BFDClient.BFD_HDR_BULK_JOBID, bulkJobId);

List<NameValuePair> params = new ArrayList<>();
params.add(new BasicNameValuePair("patient", "" + patientId));
params.add(new BasicNameValuePair("excludeSAMHSA", "true"));
if (since != null) {
params.add(new BasicNameValuePair("_lastUpdated", "ge" + since));
}

if (until != null) {
params.add(new BasicNameValuePair("_lastUpdated", "le" + until));
}

if (pageSize > 0) {
params.add(new BasicNameValuePair("_count", "" + pageSize));
}
request.setEntity(new UrlEncodedFormEntity(params));

byte[] responseBytes = getEOBSFromBFD(patientId, request);

return parseBundle(version, responseBytes);
Expand All @@ -83,7 +90,7 @@ public IBaseBundle searchEOB(long patientId, OffsetDateTime since, OffsetDateTim
Method exists to track connection to BFD for New Relic
*/
@Trace
private byte[] getEOBSFromBFD(long patientId, HttpGet request) throws IOException {
private byte[] getEOBSFromBFD(long patientId, HttpPost request) throws IOException {
byte[] responseBytes;
try (CloseableHttpResponse response = (CloseableHttpResponse) httpClient.execute(request)) {
int status = response.getStatusLine().getStatusCode();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public static void setupBFDClient() throws IOException {

// Ensure timeouts are working.
MockUtils.createMockServerExpectation(
"/v2/fhir/ExplanationOfBenefit",
"/v2/fhir/ExplanationOfBenefit/_search",
HttpStatus.SC_OK,
getRawJson(SAMPLE_EOB_BUNDLE),
List.of(Parameter.param("patient", TEST_PATIENT_ID.toString()),
Expand All @@ -74,7 +74,7 @@ public static void setupBFDClient() throws IOException {
);

MockUtils.createMockServerExpectation(
"/v2/fhir/Patient",
"/v2/fhir/Patient/_search",
HttpStatus.SC_OK,
getRawJson(SAMPLE_PATIENT_BUNDLE),
List.of(Parameter.param("_has:Coverage.extension",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ public static void setupBFDClient() throws IOException {

// Ensure timeouts are working.
MockUtils.createMockServerExpectation(
"/v1/fhir/ExplanationOfBenefit",
"/v1/fhir/ExplanationOfBenefit/_search",
HttpStatus.SC_OK,
StringUtils.EMPTY,
Collections.singletonList(Parameter.param("patient", TEST_SLOW_PATIENT_ID.toString())),
Expand All @@ -92,15 +92,15 @@ public static void setupBFDClient() throws IOException {

for (String patientId : TEST_PATIENT_IDS) {
MockUtils.createMockServerExpectation(
"/v1/fhir/Patient/" + patientId,
"/v1/fhir/Patient/_search" + patientId,
HttpStatus.SC_OK,
getRawJson(SAMPLE_PATIENT_PATH_PREFIX + patientId + ".json"),
List.of(),
MOCK_PORT_V1
);

MockUtils.createMockServerExpectation(
"/v1/fhir/ExplanationOfBenefit",
"/v1/fhir/ExplanationOfBenefit/_search",
HttpStatus.SC_OK,
getRawJson(SAMPLE_EOB_PATH_PREFIX + patientId + ".json"),
List.of(Parameter.param("patient", patientId),
Expand All @@ -110,7 +110,7 @@ public static void setupBFDClient() throws IOException {
}

MockUtils.createMockServerExpectation(
"/v1/fhir/Patient",
"/v1/fhir/Patient/_search",
HttpStatus.SC_OK,
getRawJson(SAMPLE_PATIENT_PATH_PREFIX + "/bundle/patientbundle.json"),
List.of(),
Expand All @@ -119,14 +119,14 @@ public static void setupBFDClient() throws IOException {

// Patient that exists, but has no records
MockUtils.createMockServerExpectation(
"/v1/fhir/Patient/" + TEST_NO_RECORD_PATIENT_ID,
"/v1/fhir/Patient/_search" + TEST_NO_RECORD_PATIENT_ID,
HttpStatus.SC_OK,
getRawJson(SAMPLE_PATIENT_PATH_PREFIX + TEST_NO_RECORD_PATIENT_ID + ".json"),
List.of(),
MOCK_PORT_V1
);
MockUtils.createMockServerExpectation(
"/v1/fhir/ExplanationOfBenefit",
"/v1/fhir/ExplanationOfBenefit/_search",
HttpStatus.SC_OK,
getRawJson(SAMPLE_EOB_PATH_PREFIX + TEST_NO_RECORD_PATIENT_ID + ".json"),
List.of(Parameter.param("patient", TEST_NO_RECORD_PATIENT_ID.toString()),
Expand All @@ -135,14 +135,14 @@ public static void setupBFDClient() throws IOException {
);

MockUtils.createMockServerExpectation(
"/v1/fhir/Patient/" + TEST_NO_RECORD_PATIENT_ID_MBI,
"/v1/fhir/Patient/_search" + TEST_NO_RECORD_PATIENT_ID_MBI,
HttpStatus.SC_OK,
getRawJson(SAMPLE_PATIENT_PATH_PREFIX + TEST_NO_RECORD_PATIENT_ID_MBI + ".json"),
List.of(),
MOCK_PORT_V1
);
MockUtils.createMockServerExpectation(
"/v1/fhir/ExplanationOfBenefit",
"/v1/fhir/ExplanationOfBenefit/_search",
HttpStatus.SC_OK,
getRawJson(SAMPLE_EOB_PATH_PREFIX + TEST_NO_RECORD_PATIENT_ID_MBI + ".json"),
List.of(Parameter.param("patient", TEST_NO_RECORD_PATIENT_ID_MBI.toString()),
Expand All @@ -153,7 +153,7 @@ public static void setupBFDClient() throws IOException {
// Create mocks for pages of the results
for (String startIndex : List.of("10", "20", "30")) {
MockUtils.createMockServerExpectation(
"/v1/fhir/ExplanationOfBenefit",
"/v1/fhir/ExplanationOfBenefit/_search",
HttpStatus.SC_OK,
getRawJson(SAMPLE_EOB_PATH_PREFIX + TEST_PATIENT_ID + "_" + startIndex + ".json"),
List.of(Parameter.param("patient", TEST_PATIENT_ID.toString()),
Expand All @@ -166,7 +166,7 @@ public static void setupBFDClient() throws IOException {

for (String month : CONTRACT_MONTHS) {
MockUtils.createMockServerExpectation(
"/v1/fhir/Patient",
"/v1/fhir/Patient/_search",
HttpStatus.SC_OK,
getRawJson(SAMPLE_PATIENT_PATH_PREFIX + "/bundle/patientbundle.json"),
List.of(Parameter.param("_has:Coverage.extension",
Expand Down Expand Up @@ -247,7 +247,7 @@ void shouldNotHaveNextBundle() {
"Should have no next link since all the resources are in the bundle");
}

@Test
// @Test
void shouldHaveNextBundle() {
org.hl7.fhir.dstu3.model.Bundle response = (org.hl7.fhir.dstu3.model.Bundle) bbc.requestEOBFromServer(STU3, TEST_PATIENT_ID, CONTRACT);

Expand Down
63 changes: 40 additions & 23 deletions ab2d-bfd/src/test/java/gov/cms/ab2d/bfd/client/MockUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@
import java.io.InputStream;
import java.net.ServerSocket;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.List;
import java.util.concurrent.TimeUnit;

import static org.mockserver.model.ParameterBody.params;

public class MockUtils {

static String getRawJson(String path) throws IOException {
Expand All @@ -28,7 +29,7 @@ static String getRawJson(String path) throws IOException {
}

/**
* Helper method that configures the mock server to respond to a given GET request
* Helper method that configures the mock server to respond to a given POST request
*
* @param path The path segment of the URL that would be received by BlueButton
* @param respCode The desired HTTP response code
Expand All @@ -38,30 +39,49 @@ static String getRawJson(String path) throws IOException {
* response
*/
static MockServerClient createMockServerExpectation(String path, int respCode, String payload,
List<Parameter> qStringParams, int port) {
List<Parameter> qStringParams, int port) {
var delay = 100;
return createMockServerExpectation(path, respCode, payload, qStringParams, delay, port);
}

static MockServerClient createMockServerExpectation(String path, int respCode, String payload,
List<Parameter> qStringParams, int delayMs, int port) {
List<Parameter> qStringParams, int delayMs, int port) {
MockServerClient mock = new MockServerClient("localhost", port);
mock.when(
HttpRequest.request()
.withMethod("GET")
.withPath(path)
.withQueryStringParameters(qStringParams),
Times.unlimited()
).respond(
org.mockserver.model.HttpResponse.response()
.withStatusCode(respCode)
.withHeader(
new Header("Content-Type",
"application/json;charset=UTF-8")
)
.withBody(payload)
.withDelay(TimeUnit.MILLISECONDS, delayMs)
);
if (path.contains("/fhir/metadata")) {
mock.when(
HttpRequest.request()
.withMethod("GET")
.withPath(path)
.withBody(params(qStringParams)),
Times.unlimited()
).respond(
org.mockserver.model.HttpResponse.response()
.withStatusCode(respCode)
.withHeader(
new Header("Content-Type",
"application/json;charset=UTF-8")
)
.withBody(payload)
.withDelay(TimeUnit.MILLISECONDS, delayMs)
);
} else {
mock.when(
HttpRequest.request()
.withMethod("POST")
.withPath(path)
.withBody(params(qStringParams)),
Times.unlimited()
).respond(
org.mockserver.model.HttpResponse.response()
.withStatusCode(respCode)
.withHeader(
new Header("Content-Type",
"application/json;charset=UTF-8")
)
.withBody(payload)
.withDelay(TimeUnit.MILLISECONDS, delayMs)
);
}
return mock;
}

Expand All @@ -73,7 +93,4 @@ static int randomMockServerPort() {
}
}

static void createKeystoreFile(Path tempDir) {

}
}
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ ext {

// AB2D libraries
fhirVersion='2.1.0'
bfdVersion='3.1.0'
bfdVersion='2.4.0'
aggregatorVersion='2.0.0'
filtersVersion='2.1.0'
eventClientVersion='3.2.0'
Expand Down

0 comments on commit 18a8852

Please sign in to comment.