Get patch working (#1449)

This commit is contained in:
James Agnew 2019-08-27 05:42:15 -04:00 committed by GitHub
parent e5c8ffdc20
commit 70d0a8aa8f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 79 additions and 0 deletions

View File

@ -21,19 +21,24 @@ package ca.uhn.fhir.jpa.dao.dstu3;
*/ */
import ca.uhn.fhir.jpa.dao.TransactionProcessor; import ca.uhn.fhir.jpa.dao.TransactionProcessor;
import ca.uhn.fhir.rest.api.PatchTypeEnum;
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException; import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import org.hl7.fhir.dstu3.model.Bundle; import org.hl7.fhir.dstu3.model.Bundle;
import org.hl7.fhir.dstu3.model.OperationOutcome; import org.hl7.fhir.dstu3.model.OperationOutcome;
import org.hl7.fhir.dstu3.model.Resource; import org.hl7.fhir.dstu3.model.Resource;
import org.hl7.fhir.dstu3.model.codesystems.IssueType; import org.hl7.fhir.dstu3.model.codesystems.IssueType;
import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.instance.model.api.IBaseBinary;
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome; import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import static org.apache.commons.lang3.StringUtils.isBlank;
public class TransactionProcessorVersionAdapterDstu3 implements TransactionProcessor.ITransactionProcessorVersionAdapter<Bundle, Bundle.BundleEntryComponent> { public class TransactionProcessorVersionAdapterDstu3 implements TransactionProcessor.ITransactionProcessorVersionAdapter<Bundle, Bundle.BundleEntryComponent> {
@Override @Override
public void setResponseStatus(Bundle.BundleEntryComponent theBundleEntry, String theStatus) { public void setResponseStatus(Bundle.BundleEntryComponent theBundleEntry, String theStatus) {
@ -106,6 +111,22 @@ public class TransactionProcessorVersionAdapterDstu3 implements TransactionProce
if (value != null) { if (value != null) {
retVal = value.toCode(); retVal = value.toCode();
} }
/*
* This is a workaround for the fact that PATCH isn't a valid constant for
* DSTU3 Bundle.entry.request.method (it was added in R4)
*/
if (isBlank(retVal)) {
if (theEntry.getResource() instanceof IBaseBinary) {
String contentType = ((IBaseBinary) theEntry.getResource()).getContentType();
try {
PatchTypeEnum.forContentTypeOrThrowInvalidRequestException(contentType);
retVal = "PATCH";
} catch (InvalidRequestException e) {
// ignore
}
}
}
return retVal; return retVal;
} }

View File

@ -4,11 +4,19 @@ import static org.hamcrest.Matchers.*;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import ca.uhn.fhir.rest.api.Constants;
import com.google.common.base.Charsets;
import org.apache.commons.io.IOUtils;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
@ -180,6 +188,50 @@ public class SystemProviderTransactionSearchDstu3Test extends BaseJpaDstu3Test {
assertThat(actualIds, contains(ids.subList(5, 10).toArray(new String[0]))); assertThat(actualIds, contains(ids.subList(5, 10).toArray(new String[0])));
} }
@Test
public void testPatchUsingJsonPatch_Transaction() throws Exception {
String methodName = "testPatchUsingJsonPatch_Transaction";
IIdType pid1;
{
Patient patient = new Patient();
patient.setActive(true);
patient.addIdentifier().setSystem("urn:system").setValue("0");
patient.addName().setFamily(methodName).addGiven("Joe");
pid1 = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
}
String patchString = "[ { \"op\":\"replace\", \"path\":\"/active\", \"value\":false } ]";
Binary patch = new Binary();
patch.setContentType(ca.uhn.fhir.rest.api.Constants.CT_JSON_PATCH);
patch.setContent(patchString.getBytes(Charsets.UTF_8));
// Note that we don't set the type
Bundle input = new Bundle();
input.setType(Bundle.BundleType.TRANSACTION);
input.addEntry()
.setFullUrl(pid1.getValue())
.setResource(patch)
.getRequest().setUrl(pid1.getValue());
HttpPost post = new HttpPost(ourServerBase);
String encodedRequest = myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(input);
ourLog.info("Requet:\n{}", encodedRequest);
post.setEntity(new StringEntity(encodedRequest, ContentType.parse(ca.uhn.fhir.rest.api.Constants.CT_FHIR_JSON_NEW+ Constants.CHARSET_UTF8_CTSUFFIX)));
try (CloseableHttpResponse response = ourHttpClient.execute(post)) {
String responseString = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
ourLog.info(responseString);
assertEquals(200, response.getStatusLine().getStatusCode());
assertThat(responseString, containsString("\"resourceType\":\"Bundle\""));
}
Patient newPt = ourClient.read().resource(Patient.class).withId(pid1.getIdPart()).execute();
assertEquals("2", newPt.getIdElement().getVersionIdPart());
assertEquals(false, newPt.getActive());
}
@Test @Test
public void testTransactionWithGetHardLimitLargeSynchronous() { public void testTransactionWithGetHardLimitLargeSynchronous() {
List<String> ids = create20Patients(); List<String> ids = create20Patients();

View File

@ -73,6 +73,12 @@
The informational message returned in an OperationOutcome when a delete failed due to cascades not being enabled The informational message returned in an OperationOutcome when a delete failed due to cascades not being enabled
contained an incorrect example. This has been corrected. contained an incorrect example. This has been corrected.
</action> </action>
<action type="add">
It is now possible to submit a PATCH request as a part of a FHIR transaction in DSTU3 (previously this
was only supported in R4+). This is not officially part of the DSTU3 spec, but it can now be performed by
leaving the Bundle.entry.request.method blank in DSTU3 transactions and setting the request payload
as a Binary resource containing a valid patch.
</action>
<action type="change" issue="1366"> <action type="change" issue="1366">
The HAPI FHIR CLI server now uses H2 as its database platform instead of Derby. The HAPI FHIR CLI server now uses H2 as its database platform instead of Derby.
Note that this means that data in any existing installations will need to be Note that this means that data in any existing installations will need to be