[[webflux-client-body]] = Request Body The request body can be encoded from any asynchronous type handled by `ReactiveAdapterRegistry`, like `Mono` or Kotlin Coroutines `Deferred` as the following example shows: [tabs] ====== Java:: + [source,java,indent=0,subs="verbatim,quotes",role="primary"] ---- Mono personMono = ... ; Mono result = client.post() .uri("/persons/{id}", id) .contentType(MediaType.APPLICATION_JSON) .body(personMono, Person.class) .retrieve() .bodyToMono(Void.class); ---- Kotlin:: + [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] ---- val personDeferred: Deferred = ... client.post() .uri("/persons/{id}", id) .contentType(MediaType.APPLICATION_JSON) .body(personDeferred) .retrieve() .awaitBody() ---- ====== You can also have a stream of objects be encoded, as the following example shows: [tabs] ====== Java:: + [source,java,indent=0,subs="verbatim,quotes",role="primary"] ---- Flux personFlux = ... ; Mono result = client.post() .uri("/persons/{id}", id) .contentType(MediaType.APPLICATION_STREAM_JSON) .body(personFlux, Person.class) .retrieve() .bodyToMono(Void.class); ---- Kotlin:: + [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] ---- val people: Flow = ... client.post() .uri("/persons/{id}", id) .contentType(MediaType.APPLICATION_JSON) .body(people) .retrieve() .awaitBody() ---- ====== Alternatively, if you have the actual value, you can use the `bodyValue` shortcut method, as the following example shows: [tabs] ====== Java:: + [source,java,indent=0,subs="verbatim,quotes",role="primary"] ---- Person person = ... ; Mono result = client.post() .uri("/persons/{id}", id) .contentType(MediaType.APPLICATION_JSON) .bodyValue(person) .retrieve() .bodyToMono(Void.class); ---- Kotlin:: + [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] ---- val person: Person = ... client.post() .uri("/persons/{id}", id) .contentType(MediaType.APPLICATION_JSON) .bodyValue(person) .retrieve() .awaitBody() ---- ====== [[webflux-client-body-form]] == Form Data To send form data, you can provide a `MultiValueMap` as the body. Note that the content is automatically set to `application/x-www-form-urlencoded` by the `FormHttpMessageWriter`. The following example shows how to use `MultiValueMap`: [tabs] ====== Java:: + [source,java,indent=0,subs="verbatim,quotes",role="primary"] ---- MultiValueMap formData = ... ; Mono result = client.post() .uri("/path", id) .bodyValue(formData) .retrieve() .bodyToMono(Void.class); ---- Kotlin:: + [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] ---- val formData: MultiValueMap = ... client.post() .uri("/path", id) .bodyValue(formData) .retrieve() .awaitBody() ---- ====== You can also supply form data in-line by using `BodyInserters`, as the following example shows: [tabs] ====== Java:: + [source,java,indent=0,subs="verbatim,quotes",role="primary"] ---- import static org.springframework.web.reactive.function.BodyInserters.*; Mono result = client.post() .uri("/path", id) .body(fromFormData("k1", "v1").with("k2", "v2")) .retrieve() .bodyToMono(Void.class); ---- Kotlin:: + [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] ---- import org.springframework.web.reactive.function.BodyInserters.* client.post() .uri("/path", id) .body(fromFormData("k1", "v1").with("k2", "v2")) .retrieve() .awaitBody() ---- ====== [[webflux-client-body-multipart]] == Multipart Data To send multipart data, you need to provide a `MultiValueMap` whose values are either `Object` instances that represent part content or `HttpEntity` instances that represent the content and headers for a part. `MultipartBodyBuilder` provides a convenient API to prepare a multipart request. The following example shows how to create a `MultiValueMap`: [tabs] ====== Java:: + [source,java,indent=0,subs="verbatim,quotes",role="primary"] ---- MultipartBodyBuilder builder = new MultipartBodyBuilder(); builder.part("fieldPart", "fieldValue"); builder.part("filePart1", new FileSystemResource("...logo.png")); builder.part("jsonPart", new Person("Jason")); builder.part("myPart", part); // Part from a server request MultiValueMap> parts = builder.build(); ---- Kotlin:: + [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] ---- val builder = MultipartBodyBuilder().apply { part("fieldPart", "fieldValue") part("filePart1", FileSystemResource("...logo.png")) part("jsonPart", Person("Jason")) part("myPart", part) // Part from a server request } val parts = builder.build() ---- ====== In most cases, you do not have to specify the `Content-Type` for each part. The content type is determined automatically based on the `HttpMessageWriter` chosen to serialize it or, in the case of a `Resource`, based on the file extension. If necessary, you can explicitly provide the `MediaType` to use for each part through one of the overloaded builder `part` methods. Once a `MultiValueMap` is prepared, the easiest way to pass it to the `WebClient` is through the `body` method, as the following example shows: [tabs] ====== Java:: + [source,java,indent=0,subs="verbatim,quotes",role="primary"] ---- MultipartBodyBuilder builder = ...; Mono result = client.post() .uri("/path", id) .body(builder.build()) .retrieve() .bodyToMono(Void.class); ---- Kotlin:: + [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] ---- val builder: MultipartBodyBuilder = ... client.post() .uri("/path", id) .body(builder.build()) .retrieve() .awaitBody() ---- ====== If the `MultiValueMap` contains at least one non-`String` value, which could also represent regular form data (that is, `application/x-www-form-urlencoded`), you need not set the `Content-Type` to `multipart/form-data`. This is always the case when using `MultipartBodyBuilder`, which ensures an `HttpEntity` wrapper. As an alternative to `MultipartBodyBuilder`, you can also provide multipart content, inline-style, through the built-in `BodyInserters`, as the following example shows: [tabs] ====== Java:: + [source,java,indent=0,subs="verbatim,quotes",role="primary"] ---- import static org.springframework.web.reactive.function.BodyInserters.*; Mono result = client.post() .uri("/path", id) .body(fromMultipartData("fieldPart", "value").with("filePart", resource)) .retrieve() .bodyToMono(Void.class); ---- Kotlin:: + [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] ---- import org.springframework.web.reactive.function.BodyInserters.* client.post() .uri("/path", id) .body(fromMultipartData("fieldPart", "value").with("filePart", resource)) .retrieve() .awaitBody() ---- ====== [[partevent]] === `PartEvent` To stream multipart data sequentially, you can provide multipart content through `PartEvent` objects. - Form fields can be created via `FormPartEvent::create`. - File uploads can be created via `FilePartEvent::create`. You can concatenate the streams returned from methods via `Flux::concat`, and create a request for the `WebClient`. For instance, this sample will POST a multipart form containing a form field and a file. [tabs] ====== Java:: + [source,java,indent=0,subs="verbatim,quotes",role="primary"] ---- Resource resource = ... Mono result = webClient .post() .uri("https://example.com") .body(Flux.concat( FormPartEvent.create("field", "field value"), FilePartEvent.create("file", resource) ), PartEvent.class) .retrieve() .bodyToMono(String.class); ---- Kotlin:: + [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] ---- var resource: Resource = ... var result: Mono = webClient .post() .uri("https://example.com") .body( Flux.concat( FormPartEvent.create("field", "field value"), FilePartEvent.create("file", resource) ) ) .retrieve() .bodyToMono() ---- ====== On the server side, `PartEvent` objects that are received via `@RequestBody` or `ServerRequest::bodyToFlux(PartEvent.class)` can be relayed to another service via the `WebClient`.