diff --git a/docs/src/main/asciidoc/rest-client-reactive.adoc b/docs/src/main/asciidoc/rest-client-reactive.adoc index f71ffae2a80e56..1b3c12a88aa5de 100644 --- a/docs/src/main/asciidoc/rest-client-reactive.adoc +++ b/docs/src/main/asciidoc/rest-client-reactive.adoc @@ -744,35 +744,42 @@ REST Client Reactive support multipart messages. REST Client Reactive allows sending data as multipart forms. This way you can for example send files efficiently. -To send data as a multipart form, you need to create a class that would encapsulate all the fields -to be sent, e.g. +To send data as a multipart form, you can just use the regular `@RestForm` annotations: [source, java] ---- -public class FormDto { - @FormParam("file") - @PartType(MediaType.APPLICATION_OCTET_STREAM) - public File file; - - @FormParam("otherField") - @PartType(MediaType.TEXT_PLAIN) - public String textProperty; -} + @POST + @Path("/binary") + String sendMultipart(@RestForm File file, @RestForm String otherField); ---- -The method that sends a form needs to specify multipart form data as the consumed media type, e.g. +Parameters specified as `File`, `Path`, `byte[]` or `Buffer` are sent as files and default to the +`application/octet-stream` MIME type. Other `@RestForm` parameter types default to the `text/plain` +MIME type. You can override these defaults with the `@RestPart` annotation. + +Naturally, you can also group these parameters into a containing class: + [source, java] ---- + public static class Parameters { + @RestForm + File file; + + @RestForm + String otherField; + } + @POST - @Consumes(MediaType.MULTIPART_FORM_DATA) - @Produces(MediaType.TEXT_PLAIN) @Path("/binary") - String sendMultipart(@MultipartForm FormDto data); + String sendMultipart(Parameters parameters); ---- -Fields specified as `File`, `Path`, `byte[]` or `Buffer` are sent as files; as binary files for -`@PartType(MediaType.APPLICATION_OCTET_STREAM)`, as text files for other content types. -Other fields are sent as form attributes. +Any `@RestForm` parameter of the type `File`, `Path`, `byte[]` or `Buffer`, as well as any +annotated with `@PartType` automatically imply a `@Consumes(MediaType.MULTIPART_FORM_DATA)` +on the method if there is no `@Consumes` present. + +NOTE: If there are `@RestForm` parameters that are not multipart-implying, then +`@Consumes(MediaType.APPLICATION_FORM_URLENCODED)` is implied. There are a few modes in which the form data can be encoded. By default, Rest Client Reactive uses RFC1738. @@ -784,6 +791,20 @@ by specifying `quarkus.rest-client.multipart-post-encoder-mode` in your clients created with the `@RegisterRestClient` annotation. All the available modes are described in the link:https://netty.io/4.1/api/io/netty/handler/codec/http/multipart/HttpPostRequestEncoder.EncoderMode.html[Netty documentation] +You can also send JSON multiparts by specifying the `@PartType` annotation: + +[source, java] +---- + public static class Person { + public String firstName; + public String lastName; + } + + @POST + @Path("/json") + String sendMultipart(@RestForm @RestPart(MediaType.APPLICATION_JSON) Person person); +---- + === Receiving Multipart Messages REST Client Reactive also supports receiving multipart messages. As with sending, to parse a multipart response, you need to create a class that describes the response data, e.g. @@ -809,7 +830,7 @@ Then, create an interface method that corresponds to the call and make it return @GET @Produces(MediaType.MULTIPART_FORM_DATA) @Path("/get-file") - FormDto data sendMultipart(); + FormDto data receiveMultipart(); ---- At the moment, multipart response support is subject to the following limitations: diff --git a/docs/src/main/asciidoc/resteasy-reactive.adoc b/docs/src/main/asciidoc/resteasy-reactive.adoc index 6dd71d9fde3994..8e54149940c596 100644 --- a/docs/src/main/asciidoc/resteasy-reactive.adoc +++ b/docs/src/main/asciidoc/resteasy-reactive.adoc @@ -305,12 +305,13 @@ public class Endpoint { @RestHeader("X-Cheese-Secret-Handshake") String secretHandshake, @RestForm String smell) { - return type + "/" + variant + "/" + age + "/" + level + "/" + secretHandshake + "/" + smell; + return type + "/" + variant + "/" + age + "/" + level + "/" + + secretHandshake + "/" + smell; } } ---- -NOTE: the link:{resteasy-reactive-common-api}/org/jboss/resteasy/reactive/RestPath.html[`@RestPath`] +NOTE: The link:{resteasy-reactive-common-api}/org/jboss/resteasy/reactive/RestPath.html[`@RestPath`] annotation is optional: any parameter whose name matches an existing URI template variable will be automatically assumed to have link:{resteasy-reactive-common-api}/org/jboss/resteasy/reactive/RestPath.html[`@RestPath`]. @@ -324,6 +325,59 @@ but they require you to specify the parameter name. See <> for more advanced use-cases. +==== Grouping parameters in a custom class +[[parameter-grouping]] + +You can group your request parameters in a container class instead of declaring them as method parameters to you endpoint, +so we can rewrite the previous example like this: + +[source,java] +---- +package org.acme.rest; + +import javax.ws.rs.POST; +import javax.ws.rs.Path; + +import org.jboss.resteasy.reactive.RestCookie; +import org.jboss.resteasy.reactive.RestForm; +import org.jboss.resteasy.reactive.RestHeader; +import org.jboss.resteasy.reactive.RestMatrix; +import org.jboss.resteasy.reactive.RestPath; +import org.jboss.resteasy.reactive.RestQuery; + +@Path("/cheeses/{type}") +public class Endpoint { + + public static class Parameters { + @RestPath + String type; + + @RestMatrix + String variant; + + @RestQuery + String age; + + @RestCookie + String level; + + @RestHeader("X-Cheese-Secret-Handshake") + String secretHandshake; + + @RestForm + String smell; + } + + @POST + public String allParams(Parameters parameters) { + return parameters.type + "/" + parameters.variant + "/" + parameters.age + + "/" + parameters.level + "/" + parameters.secretHandshake + + "/" + parameters.smell; + } +} +---- + + === Declaring URI parameters [[uri-parameters]] @@ -411,35 +465,44 @@ NOTE: You can add support for more <>. [[multipart]] === Handling Multipart Form data -To handle HTTP requests that have `multipart/form-data` as their content type, RESTEasy Reactive introduces the -link:{resteasy-reactive-common-api}/org/jboss/resteasy/reactive/MultipartForm.html[`@MultipartForm`] annotation. +To handle HTTP requests that have `multipart/form-data` as their content type, you can use the regular +link:{resteasy-reactive-common-api}/org/jboss/resteasy/reactive/RestForm.html[`@RestForm`] annotation, but we have special types +that allow you to access the parts as files or as entities. Let us look at an example of its use. -Assuming an HTTP request containing a file upload and a form value containing a string description need to be handled, we could write a POJO -that will hold this information like so: +Assuming an HTTP request containing a file upload, a JSON entity and a form value containing a string description, we could write +the following endpoint: [source,java] ---- +import javax.ws.rs.POST; +import javax.ws.rs.Path; import javax.ws.rs.core.MediaType; import org.jboss.resteasy.reactive.PartType; import org.jboss.resteasy.reactive.RestForm; import org.jboss.resteasy.reactive.multipart.FileUpload; -public class FormData { - - @RestForm - @PartType(MediaType.TEXT_PLAIN) - public String description; - - @RestForm("image") - public FileUpload file; +@Path("multipart") +public class MultipartResource { + public static class Person { + public String firstName; + public String lastName; + } + + @POST + public void multipart(@RestForm String description, + @RestForm("image") FileUpload file, + @RestForm @PartType(MediaType.APPLICATION_JSON) Person person) { + // do something + } } ---- -The `name` field will contain the data contained in the part of HTTP request called `description` (because +The `name` parameter will contain the data contained in the part of HTTP request called `description` (because link:{resteasy-reactive-common-api}/org/jboss/resteasy/reactive/RestForm.html[`@RestForm`] does not define a value, the field name is used), -while the `file` field will contain data about the uploaded file in the `image` part of HTTP request. +while the `file` parameter will contain data about the uploaded file in the `image` part of HTTP request, and +the `person` parameter will read the `Person` entity using the `JSON` <>. The size of every part in a multipart request must conform to the value of `quarkus.http.limits.max-form-attribute-size`, for which the default is 2048 bytes. Any request with a part size exceeding this configuration will result in HTTP status code 413. @@ -447,41 +510,13 @@ Any request with a part size exceeding this configuration will result in HTTP st NOTE: link:{resteasy-reactive-common-api}/org/jboss/resteasy/reactive/multipart/FileUpload.html[`FileUpload`] provides access to various metadata of the uploaded file. If however all you need is a handle to the uploaded file, `java.nio.file.Path` or `java.io.File` could be used. -NOTE: When access to all uploaded files without specifying the form names is needed, RESTEasy Reactive allows the use of `@RestForm List`, where it is important to **not** set a name for the link:{resteasy-reactive-common-api}/org/jboss/resteasy/reactive/RestForm.html[`@RestForm`] annotation. +If you need access to all uploaded files for all parts regardless of their names, you can do it with `@RestForm(FileUpload.ALL) List`. NOTE: link:{resteasy-reactive-common-api}/org/jboss/resteasy/reactive/PartType.html[`@PartType`] is used to aid -in deserialization of the corresponding part of the request into the desired Java type. It is very useful when -for example the corresponding body part is JSON and needs to be converted to a POJO. - -This POJO could be used in a Resource method like so: - -[source,java] ----- -import javax.ws.rs.Consumes; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.core.MediaType; - -import org.jboss.resteasy.reactive.MultipartForm; - -@Path("multipart") -public class Endpoint { - - @POST - @Produces(MediaType.APPLICATION_JSON) - @Consumes(MediaType.MULTIPART_FORM_DATA) - @Path("form") - public String form(@MultipartForm FormData formData) { - // return something - } -} ----- - -The use of link:{resteasy-reactive-common-api}/org/jboss/resteasy/reactive/MultipartForm.html[`@MultipartForm`] as -method parameter makes RESTEasy Reactive handle the request as a multipart form request. +in deserialization of the corresponding part of the request into the desired Java type. It is only required if +you need to use <> for that particular parameter. -TIP: The use of `@MultipartForm` is actually unnecessary as RESTEasy Reactive can infer this information from the use of `@Consumes(MediaType.MULTIPART_FORM_DATA)` +NOTE: Just like for any other request parameter type, you can also group them into a <>. WARNING: When handling file uploads, it is very important to move the file to permanent storage (like a database, a dedicated file system or a cloud storage) in your code that handles the POJO. Otherwise, the file will no longer be accessible when the request terminates.