forked from quarkusio/quarkus
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request quarkusio#38031 from geoand/rest-client-multipart-api
Expose an API for programmatically creating multipart requests in reactive REST Client
- Loading branch information
Showing
5 changed files
with
221 additions
and
99 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
107 changes: 107 additions & 0 deletions
107
...nt/src/test/java/io/quarkus/rest/client/reactive/multipart/MultipartProgrammaticTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
package io.quarkus.rest.client.reactive.multipart; | ||
|
||
import static org.assertj.core.api.Assertions.assertThat; | ||
|
||
import java.io.FileInputStream; | ||
import java.net.URI; | ||
import java.util.concurrent.atomic.AtomicLong; | ||
import java.util.function.Function; | ||
|
||
import jakarta.ws.rs.Consumes; | ||
import jakarta.ws.rs.FormParam; | ||
import jakarta.ws.rs.POST; | ||
import jakarta.ws.rs.Path; | ||
import jakarta.ws.rs.core.MediaType; | ||
|
||
import org.eclipse.microprofile.rest.client.RestClientBuilder; | ||
import org.jboss.logging.Logger; | ||
import org.jboss.resteasy.reactive.client.api.ClientMultipartForm; | ||
import org.jboss.resteasy.reactive.multipart.FileUpload; | ||
import org.junit.jupiter.api.Test; | ||
import org.junit.jupiter.api.extension.RegisterExtension; | ||
|
||
import io.quarkus.test.QuarkusUnitTest; | ||
import io.quarkus.test.common.http.TestHTTPResource; | ||
import io.smallrye.mutiny.Multi; | ||
|
||
public class MultipartProgrammaticTest { | ||
|
||
private static final Logger log = Logger.getLogger(MultipartProgrammaticTest.class); | ||
|
||
private static final int BYTES_SENT = 5_000_000; // 5 megs | ||
|
||
@RegisterExtension | ||
static final QuarkusUnitTest TEST = new QuarkusUnitTest() | ||
.withApplicationRoot((jar) -> jar | ||
.addClasses(Resource.class, FormData.class, Client.class)); | ||
|
||
@TestHTTPResource | ||
URI baseUri; | ||
|
||
@Test | ||
void shouldUploadBiggishFile() { | ||
Client client = RestClientBuilder.newBuilder().baseUri(baseUri).build(Client.class); | ||
|
||
AtomicLong i = new AtomicLong(); | ||
Multi<Byte> content = Multi.createBy().repeating().supplier( | ||
() -> (byte) ((i.getAndIncrement() + 1) % 123)).atMost(BYTES_SENT); | ||
String result = client.postMultipart(ClientMultipartForm.create() | ||
.multiAsBinaryFileUpload("fileFormName", "fileName", content, MediaType.APPLICATION_OCTET_STREAM) | ||
.stringFileUpload("otherFormName", "whatever", "test", MediaType.TEXT_PLAIN)); | ||
assertThat(result).isEqualTo("fileFormName/fileName-test"); | ||
} | ||
|
||
@Path("/multipart") | ||
public interface Client { | ||
@POST | ||
@Consumes(MediaType.MULTIPART_FORM_DATA) | ||
String postMultipart(ClientMultipartForm form); | ||
} | ||
|
||
@Path("/multipart") | ||
public static class Resource { | ||
@Path("/") | ||
@POST | ||
@Consumes(MediaType.MULTIPART_FORM_DATA) | ||
public String upload(FormData form) { | ||
return verifyFile(form.file, BYTES_SENT, position -> (byte) (((1 + position) % 123))) + "-" + form.other; | ||
} | ||
|
||
private String verifyFile(FileUpload upload, int expectedSize, Function<Integer, Byte> expectedByte) { | ||
var uploadedFile = upload.uploadedFile(); | ||
int size; | ||
|
||
try (FileInputStream inputStream = new FileInputStream(uploadedFile.toFile())) { | ||
int position = 0; | ||
int b; | ||
while ((b = inputStream.read()) != -1) { | ||
long expected = expectedByte.apply(position); | ||
position++; | ||
if (expected != b) { | ||
throw new RuntimeException( | ||
"WRONG_BYTE_READ at pos " + (position - 1) + " expected: " + expected + " got: " + b); | ||
} | ||
} | ||
size = position; | ||
} catch (RuntimeException e) { | ||
return e.getMessage(); | ||
} catch (Exception e) { | ||
log.error("Unexpected error in the test resource", e); | ||
return "UNEXPECTED ERROR"; | ||
} | ||
|
||
if (size != expectedSize) { | ||
return "READ_WRONG_AMOUNT_OF_BYTES " + size; | ||
} | ||
return upload.name() + "/" + upload.fileName(); | ||
} | ||
} | ||
|
||
public static class FormData { | ||
@FormParam("fileFormName") | ||
public FileUpload file; | ||
|
||
@FormParam("otherFormName") | ||
public String other; | ||
} | ||
} |
89 changes: 89 additions & 0 deletions
89
...ent/runtime/src/main/java/org/jboss/resteasy/reactive/client/api/ClientMultipartForm.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
package org.jboss.resteasy.reactive.client.api; | ||
|
||
import java.nio.charset.Charset; | ||
import java.nio.charset.StandardCharsets; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
import org.jboss.resteasy.reactive.client.impl.multipart.QuarkusMultipartForm; | ||
import org.jboss.resteasy.reactive.client.impl.multipart.QuarkusMultipartFormDataPart; | ||
|
||
import io.smallrye.mutiny.Multi; | ||
import io.vertx.core.buffer.Buffer; | ||
|
||
/** | ||
* This class allows programmatic creation of multipart requests | ||
*/ | ||
public abstract class ClientMultipartForm { | ||
|
||
protected Charset charset = StandardCharsets.UTF_8; | ||
protected final List<QuarkusMultipartFormDataPart> parts = new ArrayList<>(); | ||
protected final List<QuarkusMultipartForm.PojoFieldData> pojos = new ArrayList<>(); | ||
|
||
public static ClientMultipartForm create() { | ||
return new QuarkusMultipartForm(); | ||
} | ||
|
||
public ClientMultipartForm setCharset(String charset) { | ||
return setCharset(charset != null ? Charset.forName(charset) : null); | ||
} | ||
|
||
public ClientMultipartForm setCharset(Charset charset) { | ||
this.charset = charset; | ||
return this; | ||
} | ||
|
||
public Charset getCharset() { | ||
return charset; | ||
} | ||
|
||
public ClientMultipartForm attribute(String name, String value, String filename) { | ||
parts.add(new QuarkusMultipartFormDataPart(name, value, filename)); | ||
return this; | ||
} | ||
|
||
public ClientMultipartForm entity(String name, Object entity, String mediaType, Class<?> type) { | ||
return entity(name, null, entity, mediaType, type); | ||
} | ||
|
||
public ClientMultipartForm entity(String name, String filename, Object entity, String mediaType, Class<?> type) { | ||
pojos.add(new QuarkusMultipartForm.PojoFieldData(name, filename, entity, mediaType, type, parts.size())); | ||
parts.add(null); // make place for ^ | ||
return this; | ||
} | ||
|
||
public ClientMultipartForm textFileUpload(String name, String filename, String pathname, String mediaType) { | ||
parts.add(new QuarkusMultipartFormDataPart(name, filename, pathname, mediaType, true)); | ||
return this; | ||
} | ||
|
||
public ClientMultipartForm textFileUpload(String name, String filename, Buffer content, String mediaType) { | ||
parts.add(new QuarkusMultipartFormDataPart(name, filename, content, mediaType, true)); | ||
return this; | ||
} | ||
|
||
public ClientMultipartForm stringFileUpload(String name, String filename, String content, String mediaType) { | ||
return textFileUpload(name, filename, Buffer.buffer(content), mediaType); | ||
} | ||
|
||
public ClientMultipartForm binaryFileUpload(String name, String filename, String pathname, String mediaType) { | ||
parts.add(new QuarkusMultipartFormDataPart(name, filename, pathname, mediaType, false)); | ||
return this; | ||
} | ||
|
||
public ClientMultipartForm binaryFileUpload(String name, String filename, Buffer content, String mediaType) { | ||
parts.add(new QuarkusMultipartFormDataPart(name, filename, content, mediaType, false)); | ||
return this; | ||
} | ||
|
||
public ClientMultipartForm multiAsBinaryFileUpload(String name, String filename, Multi<Byte> content, String mediaType) { | ||
parts.add(new QuarkusMultipartFormDataPart(name, filename, content, mediaType, false)); | ||
return this; | ||
} | ||
|
||
public ClientMultipartForm multiAsTextFileUpload(String name, String filename, Multi<Byte> content, String mediaType) { | ||
parts.add(new QuarkusMultipartFormDataPart(name, filename, content, mediaType, true)); | ||
return this; | ||
} | ||
|
||
} |
Oops, something went wrong.