Fix #1250 - Don't include Bundle.entry.response on search results
This commit is contained in:
parent
58e6b7f6aa
commit
638cb976fd
|
@ -35,7 +35,9 @@ public enum BundleTypeEnum {
|
|||
DOCUMENT("document", "http://hl7.org/fhir/bundle-type"),
|
||||
|
||||
MESSAGE("message", "http://hl7.org/fhir/bundle-type"),
|
||||
|
||||
|
||||
BATCH_RESPONSE("batch-response", "http://hl7.org/fhir/bundle-type"),
|
||||
|
||||
TRANSACTION_RESPONSE("transaction-response", "http://hl7.org/fhir/bundle-type"),
|
||||
|
||||
HISTORY("history", "http://hl7.org/fhir/bundle-type"),
|
||||
|
|
|
@ -9,9 +9,9 @@ package org.hl7.fhir.dstu3.hapi.rest.server;
|
|||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
@ -27,6 +27,7 @@ import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
|
|||
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.IVersionSpecificBundleFactory;
|
||||
import ca.uhn.fhir.rest.server.RestfulServerUtils;
|
||||
import ca.uhn.fhir.util.ResourceReferenceInfo;
|
||||
import org.hl7.fhir.dstu3.model.Bundle;
|
||||
import org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent;
|
||||
|
@ -127,9 +128,9 @@ public class Dstu3BundleFactory implements IVersionSpecificBundleFactory {
|
|||
|
||||
}
|
||||
|
||||
/*
|
||||
* Actually add the resources to the bundle
|
||||
*/
|
||||
/*
|
||||
* Actually add the resources to the bundle
|
||||
*/
|
||||
for (IBaseResource next : includedResources) {
|
||||
BundleEntryComponent entry = myBundle.addEntry();
|
||||
entry.setResource((Resource) next).getSearch().setMode(SearchEntryMode.INCLUDE);
|
||||
|
@ -199,7 +200,7 @@ public class Dstu3BundleFactory implements IVersionSpecificBundleFactory {
|
|||
includedResources.addAll(addedResourcesThisPass);
|
||||
|
||||
// Linked resources may themselves have linked resources
|
||||
references = new ArrayList<ResourceReferenceInfo>();
|
||||
references = new ArrayList<>();
|
||||
for (IAnyResource iResource : addedResourcesThisPass) {
|
||||
List<ResourceReferenceInfo> newReferences = myContext.newTerser().getAllResourceReferences(iResource);
|
||||
references.addAll(newReferences);
|
||||
|
@ -220,15 +221,33 @@ public class Dstu3BundleFactory implements IVersionSpecificBundleFactory {
|
|||
entry.setResource(null);
|
||||
}
|
||||
|
||||
// Populate Bundle.entry.response
|
||||
switch (theBundleType) {
|
||||
case BATCH_RESPONSE:
|
||||
case TRANSACTION_RESPONSE:
|
||||
case HISTORY:
|
||||
if ("1".equals(id.getVersionIdPart())) {
|
||||
entry.getResponse().setStatus("201 Created");
|
||||
} else if (isNotBlank(id.getVersionIdPart())) {
|
||||
entry.getResponse().setStatus("200 OK");
|
||||
}
|
||||
if (isNotBlank(id.getVersionIdPart())) {
|
||||
entry.getResponse().setEtag(RestfulServerUtils.createEtag(id.getVersionIdPart()));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Populate Bundle.entry.search
|
||||
String searchMode = ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE.get(nextAsResource);
|
||||
if (searchMode != null) {
|
||||
entry.getSearch().getModeElement().setValueAsString(searchMode);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Actually add the resources to the bundle
|
||||
*/
|
||||
/*
|
||||
* Actually add the resources to the bundle
|
||||
*/
|
||||
for (IAnyResource next : includedResources) {
|
||||
BundleEntryComponent entry = myBundle.addEntry();
|
||||
entry.setResource((Resource) next).getSearch().setMode(SearchEntryMode.INCLUDE);
|
||||
|
|
|
@ -223,16 +223,23 @@ public class R4BundleFactory implements IVersionSpecificBundleFactory {
|
|||
entry.setResource(null);
|
||||
}
|
||||
|
||||
// Populate Response
|
||||
if ("1".equals(id.getVersionIdPart())) {
|
||||
entry.getResponse().setStatus("201 Created");
|
||||
} else if (isNotBlank(id.getVersionIdPart())) {
|
||||
entry.getResponse().setStatus("200 OK");
|
||||
}
|
||||
if (isNotBlank(id.getVersionIdPart())) {
|
||||
entry.getResponse().setEtag(RestfulServerUtils.createEtag(id.getVersionIdPart()));
|
||||
// Populate Bundle.entry.response
|
||||
switch (theBundleType) {
|
||||
case BATCH_RESPONSE:
|
||||
case TRANSACTION_RESPONSE:
|
||||
case HISTORY:
|
||||
if ("1".equals(id.getVersionIdPart())) {
|
||||
entry.getResponse().setStatus("201 Created");
|
||||
} else if (isNotBlank(id.getVersionIdPart())) {
|
||||
entry.getResponse().setStatus("200 OK");
|
||||
}
|
||||
if (isNotBlank(id.getVersionIdPart())) {
|
||||
entry.getResponse().setEtag(RestfulServerUtils.createEtag(id.getVersionIdPart()));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Populate Bundle.entry.search
|
||||
String searchMode = ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE.get(nextAsResource);
|
||||
if (searchMode != null) {
|
||||
entry.getSearch().getModeElement().setValueAsString(searchMode);
|
||||
|
|
|
@ -2,6 +2,8 @@ package ca.uhn.fhir.rest.server;
|
|||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.model.api.Include;
|
||||
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
|
||||
import ca.uhn.fhir.model.valueset.BundleEntrySearchModeEnum;
|
||||
import ca.uhn.fhir.rest.annotation.IncludeParam;
|
||||
import ca.uhn.fhir.rest.annotation.RequiredParam;
|
||||
import ca.uhn.fhir.rest.annotation.Search;
|
||||
|
@ -15,6 +17,8 @@ import ca.uhn.fhir.rest.param.TokenAndListParam;
|
|||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import ca.uhn.fhir.util.UrlUtil;
|
||||
import ca.uhn.fhir.validation.FhirValidator;
|
||||
import ca.uhn.fhir.validation.ValidationResult;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.client.ClientProtocolException;
|
||||
|
@ -28,6 +32,7 @@ import org.eclipse.jetty.servlet.ServletHandler;
|
|||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.hl7.fhir.r4.utils.IResourceValidator;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
|
@ -64,20 +69,18 @@ public class SearchR4Test {
|
|||
}
|
||||
|
||||
private Bundle executeAndReturnLinkNext(HttpGet httpGet, EncodingEnum theExpectEncoding) throws IOException, ClientProtocolException {
|
||||
CloseableHttpResponse status = ourClient.execute(httpGet);
|
||||
Bundle bundle;
|
||||
try {
|
||||
try (CloseableHttpResponse status = ourClient.execute(httpGet)) {
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
ourLog.info(responseContent);
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
EncodingEnum ct = EncodingEnum.forContentType(status.getEntity().getContentType().getValue().replaceAll(";.*", "").trim());
|
||||
assertEquals(theExpectEncoding, ct);
|
||||
bundle = ct.newParser(ourCtx).parseResource(Bundle.class, responseContent);
|
||||
validate(bundle);
|
||||
assertEquals(10, bundle.getEntry().size());
|
||||
String linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
|
||||
assertNotNull(linkNext);
|
||||
} finally {
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
}
|
||||
return bundle;
|
||||
}
|
||||
|
@ -346,19 +349,17 @@ public class SearchR4Test {
|
|||
|
||||
@Test
|
||||
public void testSearchNormal() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?identifier=foo%7Cbar");
|
||||
CloseableHttpResponse status = ourClient.execute(httpGet);
|
||||
try {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?identifier=foo%7Cbar&_pretty=true");
|
||||
try (CloseableHttpResponse status = ourClient.execute(httpGet)) {
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
ourLog.info(responseContent);
|
||||
validate(ourCtx.newJsonParser().parseResource(responseContent));
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
|
||||
assertEquals("search", ourLastMethod);
|
||||
|
||||
assertEquals("foo", ourIdentifiers.getValuesAsQueryTokens().get(0).getValuesAsQueryTokens().get(0).getSystem());
|
||||
assertEquals("bar", ourIdentifiers.getValuesAsQueryTokens().get(0).getValuesAsQueryTokens().get(0).getValue());
|
||||
} finally {
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -366,8 +367,7 @@ public class SearchR4Test {
|
|||
@Test
|
||||
public void testSearchWithInvalidChain() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?identifier.chain=foo%7Cbar");
|
||||
CloseableHttpResponse status = ourClient.execute(httpGet);
|
||||
try {
|
||||
try (CloseableHttpResponse status = ourClient.execute(httpGet)) {
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
ourLog.info(responseContent);
|
||||
assertEquals(400, status.getStatusLine().getStatusCode());
|
||||
|
@ -376,14 +376,12 @@ public class SearchR4Test {
|
|||
assertEquals(
|
||||
"Invalid search parameter \"identifier.chain\". Parameter contains a chain (.chain) and chains are not supported for this parameter (chaining is only allowed on reference parameters)",
|
||||
oo.getIssueFirstRep().getDiagnostics());
|
||||
} finally {
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchWithPostAndInvalidParameters() throws Exception {
|
||||
public void testSearchWithPostAndInvalidParameters() {
|
||||
IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort);
|
||||
LoggingInterceptor interceptor = new LoggingInterceptor();
|
||||
interceptor.setLogRequestSummary(true);
|
||||
|
@ -414,6 +412,15 @@ public class SearchR4Test {
|
|||
return ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(theBundle);
|
||||
}
|
||||
|
||||
protected void validate(IBaseResource theResource) {
|
||||
FhirValidator validatorModule = ourCtx.newValidator();
|
||||
ValidationResult result = validatorModule.validateWithResult(theResource);
|
||||
if (!result.isSuccessful()) {
|
||||
fail(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(result.toOperationOutcome()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class DummyPatientResourceProvider implements IResourceProvider {
|
||||
|
||||
@Override
|
||||
|
@ -427,13 +434,14 @@ public class SearchR4Test {
|
|||
@RequiredParam(name = Patient.SP_IDENTIFIER) TokenAndListParam theIdentifiers) {
|
||||
ourLastMethod = "search";
|
||||
ourIdentifiers = theIdentifiers;
|
||||
ArrayList<Patient> retVal = new ArrayList<Patient>();
|
||||
ArrayList<Patient> retVal = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < 200; i++) {
|
||||
Patient patient = new Patient();
|
||||
patient.getIdElement().setValue("Patient/" + i + "/_history/222");
|
||||
ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE.put(patient, BundleEntrySearchModeEnum.INCLUDE.getCode());
|
||||
patient.addName(new HumanName().setFamily("FAMILY"));
|
||||
patient.setActive(true);
|
||||
patient.getIdElement().setValue("Patient/" + i);
|
||||
retVal.add(patient);
|
||||
}
|
||||
return retVal;
|
||||
|
|
|
@ -106,6 +106,12 @@
|
|||
a resource in an entry that required a resource (e.g. a POST). Thanks to
|
||||
GitHub user @lytvynenko-dmitriy for reporting!
|
||||
</action>
|
||||
<action type="fix" issue="1250">
|
||||
HAPI FHIR Server (plain, JPA, and JAX-RS) all populated Bundle.entry.result
|
||||
on search result bundles, even though the FHIR specification states that this
|
||||
should not be populated. This has been corrected. Thanks to GitHub user
|
||||
@gitrust for reporting!
|
||||
</action>
|
||||
</release>
|
||||
<release version="3.8.0" date="2019-05-30" description="Hippo">
|
||||
<action type="fix">
|
||||
|
|
Loading…
Reference in New Issue