diff --git a/connectors/http/http-base/src/main/java/io/camunda/connector/http/base/client/apache/builder/parts/ApacheRequestBodyBuilder.java b/connectors/http/http-base/src/main/java/io/camunda/connector/http/base/client/apache/builder/parts/ApacheRequestBodyBuilder.java index d3f886c220..022544e201 100644 --- a/connectors/http/http-base/src/main/java/io/camunda/connector/http/base/client/apache/builder/parts/ApacheRequestBodyBuilder.java +++ b/connectors/http/http-base/src/main/java/io/camunda/connector/http/base/client/apache/builder/parts/ApacheRequestBodyBuilder.java @@ -28,6 +28,7 @@ import io.camunda.zeebe.client.api.response.DocumentMetadata; import java.io.BufferedInputStream; import java.nio.charset.StandardCharsets; +import java.util.List; import java.util.Map; import java.util.Optional; import java.util.stream.Collectors; @@ -128,6 +129,7 @@ private HttpEntity createMultiPartEntity(Map body, ContentType contentType for (Map.Entry entry : body.entrySet()) { switch (entry.getValue()) { case Document document -> streamDocumentContent(entry, document, builder); + case List list -> tryStreamDocumentListContent(entry, list, builder); case null -> {} default -> builder.addTextBody( @@ -139,6 +141,17 @@ private HttpEntity createMultiPartEntity(Map body, ContentType contentType return builder.build(); } + private void tryStreamDocumentListContent( + Map.Entry entry, List list, MultipartEntityBuilder builder) { + for (Object item : list) { + if (item instanceof Document document) { + streamDocumentContent(entry, document, builder); + } else { + builder.addTextBody(String.valueOf(entry.getKey()), String.valueOf(item)); + } + } + } + private void streamDocumentContent( Map.Entry entry, Document document, MultipartEntityBuilder builder) { DocumentMetadata metadata = document.metadata(); diff --git a/connectors/http/http-base/src/test/java/io/camunda/connector/http/base/client/apache/CustomApacheHttpClientTest.java b/connectors/http/http-base/src/test/java/io/camunda/connector/http/base/client/apache/CustomApacheHttpClientTest.java index 8dc4d20e26..d830c91030 100644 --- a/connectors/http/http-base/src/test/java/io/camunda/connector/http/base/client/apache/CustomApacheHttpClientTest.java +++ b/connectors/http/http-base/src/test/java/io/camunda/connector/http/base/client/apache/CustomApacheHttpClientTest.java @@ -157,6 +157,61 @@ public void shouldReturn201_whenUploadDocument(WireMockRuntimeInfo wmRuntimeInfo .withHeader("Content-Type", equalTo("text/plain")) .build())); } + + @Test + public void shouldReturn201_whenUploadDocuments(WireMockRuntimeInfo wmRuntimeInfo) { + stubFor(post("/path").withMultipartRequestBody(aMultipart()).willReturn(created())); + var ref = + store.createDocument( + DocumentCreationRequest.from("The content of this file".getBytes()) + .fileName("file.txt") + .contentType("text/plain") + .build()); + var ref2 = + store.createDocument( + DocumentCreationRequest.from("The content of this file 2".getBytes()) + .fileName("file2.txt") + .contentType("text/plain") + .build()); + HttpCommonRequest request = new HttpCommonRequest(); + request.setMethod(HttpMethod.POST); + var bodyMap = new HashMap<>(); + bodyMap.put( + "documents", + List.of( + new CamundaDocument(ref.metadata(), ref, store), + new CamundaDocument(ref2.metadata(), ref2, store))); + bodyMap.put("otherField", "otherValue"); + bodyMap.put("nullField", null); + request.setHeaders(Map.of("Content-Type", ContentType.MULTIPART_FORM_DATA.getMimeType())); + request.setUrl(wmRuntimeInfo.getHttpBaseUrl() + "/path"); + request.setBody(bodyMap); + HttpCommonResult result = customApacheHttpClient.execute(request); + assertThat(result).isNotNull(); + assertThat(result.status()).isEqualTo(201); + + verify( + postRequestedFor(urlEqualTo("/path")) + .withHeader( + "Content-Type", and(containing("multipart/form-data"), containing("boundary="))) + .withRequestBodyPart( + new MultipartValuePatternBuilder() + .withName("otherField") + .withBody(equalTo("otherValue")) + .build()) + .withRequestBodyPart( + new MultipartValuePatternBuilder() + .withName("documents") + .withBody(equalTo("The content of this file")) + .withHeader("Content-Type", equalTo("text/plain")) + .build()) + .withRequestBodyPart( + new MultipartValuePatternBuilder() + .withName("documents") + .withBody(equalTo("The content of this file 2")) + .withHeader("Content-Type", equalTo("text/plain")) + .build())); + } } @Nested