mirror of
https://github.com/spring-projects/spring-framework.git
synced 2026-09-17 16:39:29 +00:00
Add integration tests and docs for multipart support
This commit adds integration tests and reference documentation for multipart support in `RestClient` and `RestTestClient`. Closes gh-35569 Closes gh-33263
This commit is contained in:
@@ -451,11 +451,59 @@ In most cases, you do not have to specify the `Content-Type` for each part.
|
||||
The content type is determined automatically based on the `HttpMessageConverter` chosen to serialize it or, in the case of a `Resource`, based on the file extension.
|
||||
If necessary, you can explicitly provide the `MediaType` with an `HttpEntity` wrapper.
|
||||
|
||||
The `Content-Type` is set to `multipart/form-data` by the `MultiPartHttpMessageConverter`.
|
||||
The `Content-Type` is set to `multipart/form-data` by the `MultipartHttpMessageConverter`.
|
||||
As seen in the previous section, `MultiValueMap` types can also be used for URL encoded forms.
|
||||
It is preferable to explicitly set the media type in the `Content-Type` or `Accept` HTTP request headers to ensure that the expected
|
||||
message converter is used.
|
||||
|
||||
`RestClient` can also receive multipart responses.
|
||||
To decode a multipart response body, use a `ParameterizedTypeReference<MultiValueMap<String, Part>>`.
|
||||
The decoded map contains `Part` instances where `FormFieldPart` represents form field values
|
||||
and `FilePart` represents file parts with a `filename()` and a `transferTo()` method.
|
||||
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,indent=0,subs="verbatim"]
|
||||
----
|
||||
MultiValueMap<String, Part> result = this.restClient.get()
|
||||
.uri("https://example.com/upload")
|
||||
.accept(MediaType.MULTIPART_FORM_DATA)
|
||||
.retrieve()
|
||||
.body(new ParameterizedTypeReference<>() {});
|
||||
|
||||
Part field = result.getFirst("fieldPart");
|
||||
if (field instanceof FormFieldPart formField) {
|
||||
String fieldValue = formField.value();
|
||||
}
|
||||
Part file = result.getFirst("filePart");
|
||||
if (file instanceof FilePart filePart) {
|
||||
filePart.transferTo(Path.of("/tmp/" + filePart.filename()));
|
||||
}
|
||||
----
|
||||
|
||||
Kotlin::
|
||||
+
|
||||
[source,kotlin,indent=0,subs="verbatim"]
|
||||
----
|
||||
val result = this.restClient.get()
|
||||
.uri("https://example.com/upload")
|
||||
.accept(MediaType.MULTIPART_FORM_DATA)
|
||||
.retrieve()
|
||||
.body(object : ParameterizedTypeReference<MultiValueMap<String, Part>>() {})
|
||||
|
||||
val field = result?.getFirst("fieldPart")
|
||||
if (field is FormFieldPart) {
|
||||
val fieldValue = field.value()
|
||||
}
|
||||
val file = result?.getFirst("filePart")
|
||||
if (file is FilePart) {
|
||||
file.transferTo(Path.of("/tmp/" + file.filename()))
|
||||
}
|
||||
----
|
||||
======
|
||||
|
||||
|
||||
[[rest-request-factories]]
|
||||
=== Client Request Factories
|
||||
|
||||
@@ -142,6 +142,9 @@ provides two alternative ways to verify the response:
|
||||
1. xref:resttestclient-workflow[Built-in Assertions] extend the request workflow with a chain of expectations
|
||||
2. xref:resttestclient-assertj[AssertJ Integration] to verify the response via `assertThat()` statements
|
||||
|
||||
TIP: See the xref:integration/rest-clients.adoc#rest-message-conversion[HTTP Message Conversion]
|
||||
section for examples on how to prepare a request with any content, including form data and multipart data.
|
||||
|
||||
|
||||
|
||||
[[resttestclient.workflow]]
|
||||
@@ -213,6 +216,16 @@ To verify JSON content with https://github.com/jayway/JsonPath[JSONPath]:
|
||||
include-code::./JsonTests[tag=jsonPath,indent=0]
|
||||
|
||||
|
||||
[[resttestclient.multipart]]
|
||||
==== Multipart Content
|
||||
|
||||
When testing endpoints that return multipart responses, you can decode the body to a
|
||||
`MultiValueMap<String, Part>` and assert individual parts using the `FormFieldPart`
|
||||
and `FilePart` subtypes.
|
||||
|
||||
include-code::./MultipartTests[tag=multipart,indent=0]
|
||||
|
||||
|
||||
[[resttestclient.assertj]]
|
||||
=== AssertJ Integration
|
||||
|
||||
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2025-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.docs.testing.resttestclient.multipart;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.converter.multipart.FilePart;
|
||||
import org.springframework.http.converter.multipart.FormFieldPart;
|
||||
import org.springframework.http.converter.multipart.Part;
|
||||
import org.springframework.test.web.servlet.client.RestTestClient;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class MultipartTests {
|
||||
|
||||
RestTestClient client;
|
||||
|
||||
@Test
|
||||
void multipart() {
|
||||
// tag::multipart[]
|
||||
client.get().uri("/upload")
|
||||
.accept(MediaType.MULTIPART_FORM_DATA)
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectBody(new ParameterizedTypeReference<MultiValueMap<String, Part>>() {})
|
||||
.value(result -> {
|
||||
Part field = result.getFirst("fieldPart");
|
||||
assertThat(field).isInstanceOfSatisfying(FormFieldPart.class,
|
||||
formField -> assertThat(formField.value()).isEqualTo("fieldValue"));
|
||||
Part file = result.getFirst("filePart");
|
||||
assertThat(file).isInstanceOfSatisfying(FilePart.class,
|
||||
filePart -> assertThat(filePart.filename()).isEqualTo("logo.png"));
|
||||
});
|
||||
// end::multipart[]
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user