From dbbff1fd16bee7dd96d8fa9358ead26da55cf580 Mon Sep 17 00:00:00 2001 From: James Agnew Date: Fri, 21 Aug 2020 21:00:55 -0400 Subject: [PATCH] Allow HTTP 204 response to transaction (#2051) * Allow HTTP 204 response to transaction * Add changelog * Test fix --- .../uhn/fhir/rest/client/impl/BaseClient.java | 4 +++ .../2051-allow-204-transaction-response.yaml | 5 ++++ .../rest/client/GenericClientDstu2Test.java | 27 ------------------- .../fhir/rest/client/GenericClientR4Test.java | 27 +++++++++++++++++++ 4 files changed, 36 insertions(+), 27 deletions(-) create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/5_2_0/2051-allow-204-transaction-response.yaml diff --git a/hapi-fhir-client/src/main/java/ca/uhn/fhir/rest/client/impl/BaseClient.java b/hapi-fhir-client/src/main/java/ca/uhn/fhir/rest/client/impl/BaseClient.java index 8aad6fc48d7..bb245ae08bd 100644 --- a/hapi-fhir-client/src/main/java/ca/uhn/fhir/rest/client/impl/BaseClient.java +++ b/hapi-fhir-client/src/main/java/ca/uhn/fhir/rest/client/impl/BaseClient.java @@ -567,6 +567,10 @@ public abstract class BaseClient implements IRestfulClient { @Override public T invokeClient(String theResponseMimeType, InputStream theResponseInputStream, int theResponseStatusCode, Map> theHeaders) throws BaseServerResponseException { + if (theResponseStatusCode == Constants.STATUS_HTTP_204_NO_CONTENT) { + return null; + } + EncodingEnum respType = EncodingEnum.forContentType(theResponseMimeType); if (respType == null) { if (myAllowHtmlResponse && theResponseMimeType.toLowerCase().contains(Constants.CT_HTML) && myReturnType != null) { diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/5_2_0/2051-allow-204-transaction-response.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/5_2_0/2051-allow-204-transaction-response.yaml new file mode 100644 index 00000000000..67093b148c1 --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/5_2_0/2051-allow-204-transaction-response.yaml @@ -0,0 +1,5 @@ +--- +type: add +issue: 2051 +title: The FHIR Client will now accept an HTTP 204 NO CONTENT as a response to a write operation such + as a create/update/transaction/etc. diff --git a/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/rest/client/GenericClientDstu2Test.java b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/rest/client/GenericClientDstu2Test.java index 415e46da9c4..a6b755da160 100644 --- a/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/rest/client/GenericClientDstu2Test.java +++ b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/rest/client/GenericClientDstu2Test.java @@ -2397,33 +2397,6 @@ public class GenericClientDstu2Test { assertEquals("Patient/2/_history/2", response.getEntry().get(1).getResponse().getLocation()); } - @Test - public void testTransactionHandle204NoBody() throws Exception { - - IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir"); - - ca.uhn.fhir.model.dstu2.resource.Bundle bundle = new Bundle(); - bundle.setType(BundleTypeEnum.TRANSACTION); - - ca.uhn.fhir.model.dstu2.resource.Bundle.Entry entry = bundle.addEntry(); - entry.setResource(new Patient()); - entry.getRequest().setMethod(HTTPVerbEnum.PUT); - - - - ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); - when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse); - when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), Constants.STATUS_HTTP_204_NO_CONTENT, "")); - when(myHttpResponse.getEntity() ).thenReturn(null); - - try { - client.transaction().withBundle(bundle).execute(); - fail("Should throw an exception"); - } catch (NonFhirResponseException e) { - assertEquals(Constants.STATUS_HTTP_204_NO_CONTENT, e.getStatusCode()); - } - } - @Test public void testUpdateConditional() throws Exception { ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); diff --git a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/client/GenericClientR4Test.java b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/client/GenericClientR4Test.java index ff5921f3202..2d123673c70 100644 --- a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/client/GenericClientR4Test.java +++ b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/client/GenericClientR4Test.java @@ -25,6 +25,7 @@ import ca.uhn.fhir.rest.param.DateRangeParam; import ca.uhn.fhir.rest.param.ParamPrefixEnum; import ca.uhn.fhir.rest.server.exceptions.NotImplementedOperationException; import ca.uhn.fhir.rest.server.exceptions.UnclassifiedServerFailureException; +import ca.uhn.fhir.util.TransactionBuilder; import ca.uhn.fhir.util.UrlUtil; import com.google.common.base.Charsets; import com.helger.commons.io.stream.StringInputStream; @@ -36,6 +37,7 @@ import org.apache.http.client.methods.HttpPut; import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.message.BasicHeader; import org.apache.http.message.BasicStatusLine; +import org.hl7.fhir.instance.model.api.IBaseBundle; import org.hl7.fhir.instance.model.api.IPrimitiveType; import org.hl7.fhir.r4.model.Binary; import org.hl7.fhir.r4.model.BooleanType; @@ -2106,6 +2108,31 @@ public class GenericClientR4Test extends BaseGenericClientR4Test { } + @Test + public void testTransactionWithResponseHttp204NoContent() throws IOException { + IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir"); + + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse); + when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 204, "No Content")); + when(myHttpResponse.getEntity()).thenReturn(null); + when(myHttpResponse.getAllHeaders()).thenAnswer(new Answer() { + @Override + public Header[] answer(InvocationOnMock theInvocation) { + return new Header[0]; + } + }); + + TransactionBuilder builder = new TransactionBuilder(ourCtx); + builder.addCreateEntry(new Patient().setActive(true)); + + IBaseBundle outcome = client.transaction().withBundle(builder.getBundle()).execute(); + assertNull(outcome); + + assertEquals("http://example.com/fhir", capt.getAllValues().get(0).getURI().toASCIIString()); + + } + @Test public void testUpdateById() throws Exception { IParser p = ourCtx.newXmlParser();