|
This version is still in development and is not considered stable yet. For the latest stable version, please use Spring REST Docs 4.0.0! |
Multipart
Spring REST Docs provides support for documenting multipart requests.
Request Parts
You can use requestParts to document the parts of a multipart request.
The following example shows how to do so:
-
MockMvc
-
WebTestClient
import org.junit.jupiter.api.Test;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
import static org.springframework.restdocs.request.RequestDocumentation.partWithName;
import static org.springframework.restdocs.request.RequestDocumentation.requestParts;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.multipart;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
class RequestParts {
// Fields
private MockMvc mockMvc;
@Test
void test() throws Exception {
this.mockMvc.perform(multipart("/upload").file("file", "example".getBytes())) (1)
.andExpect(status().isOk())
.andDo(document("upload", requestParts((2)
partWithName("file").description("The file to upload")) (3)
));
}
}
| 1 | Perform a POST request with a single part named file. |
| 2 | Configure Spring REST Docs to produce a snippet describing the request’s parts.
Uses the static requestParts method on org.springframework.restdocs.request.RequestDocumentation. |
| 3 | Document the part named file.
Uses the static partWithName method on org.springframework.restdocs.request.RequestDocumentation. |
import org.junit.jupiter.api.Test;
import org.springframework.test.web.reactive.server.WebTestClient;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.reactive.function.BodyInserters;
import static org.springframework.restdocs.request.RequestDocumentation.partWithName;
import static org.springframework.restdocs.request.RequestDocumentation.requestParts;
import static org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation.document;
class RequestParts {
// Fields
private WebTestClient webTestClient;
@Test
void test() {
MultiValueMap<String, Object> multipartData = new LinkedMultiValueMap<>();
multipartData.add("file", "example".getBytes());
this.webTestClient.post()
.uri("/upload")
.body(BodyInserters.fromMultipartData(multipartData)) (1)
.exchange()
.expectStatus()
.isOk()
.expectBody()
.consumeWith(document("upload", requestParts((2)
partWithName("file").description("The file to upload")) (3)
));
}
}
| 1 | Perform a POST request with a single part named file. |
| 2 | Configure Spring REST Docs to produce a snippet describing the request’s parts.
Uses the static requestParts method on org.springframework.restdocs.request.RequestDocumentation. |
| 3 | Document the part named file.
Uses the static partWithName method on org.springframework.restdocs.request.RequestDocumentation. |
The result is a snippet named request-parts.adoc that contains a table describing the request parts that are supported by the resource.
When documenting request parts, the test fails if an undocumented part is used in the request. Similarly, the test also fails if a documented part is not found in the request and the part has not been marked as optional.
You can also document request parts in a relaxed mode where any undocumented parts do not cause a test failure.
To do so, use the relaxedRequestParts method on org.springframework.restdocs.request.RequestDocumentation.
This can be useful when documenting a particular scenario where you only want to focus on a subset of the request parts.
If you do not want to document a request part, you can mark it as ignored. This prevents it from appearing in the generated snippet while avoiding the failure described earlier.
Request Part Payloads
You can document the payload of a request part in much the same way as the payload of a request, with support for documenting a request part’s body and its fields.
Documenting a Request Part’s Body
You can generate a snippet containing the body of a request part as follows:
-
MockMvc
-
WebTestClient
import org.junit.jupiter.api.Test;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.multipart;
import static org.springframework.restdocs.payload.PayloadDocumentation.requestPartBody;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
class RequestPartBody {
// Fields
private MockMvc mockMvc;
@Test
void test() throws Exception {
MockMultipartFile image = new MockMultipartFile("image", "image.png", "image/png", "<<png data>>".getBytes());
MockMultipartFile metadata = new MockMultipartFile("metadata", "", "application/json",
"{ \"version\": \"1.0\"}".getBytes());
this.mockMvc.perform(multipart("/images").file(image).file(metadata).accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andDo(document("image-upload", requestPartBody("metadata"))); (1)
}
}
| 1 | Configure Spring REST docs to produce a snippet containing the body of the request part named metadata.
Uses the static requestPartBody method on PayloadDocumentation. |
import java.util.Collections;
import org.junit.jupiter.api.Test;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.Resource;
import org.springframework.http.MediaType;
import org.springframework.test.web.reactive.server.WebTestClient;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.reactive.function.BodyInserters;
import static org.springframework.restdocs.payload.PayloadDocumentation.requestPartBody;
import static org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation.document;
class RequestPartBody {
// Fields
private WebTestClient webTestClient;
@Test
void test() {
MultiValueMap<String, Object> multipartData = new LinkedMultiValueMap<>();
Resource imageResource = new ByteArrayResource("<<png data>>".getBytes()) {
@Override
public String getFilename() {
return "image.png";
}
};
multipartData.add("image", imageResource);
multipartData.add("metadata", Collections.singletonMap("version", "1.0"));
this.webTestClient.post()
.uri("/images")
.body(BodyInserters.fromMultipartData(multipartData))
.accept(MediaType.APPLICATION_JSON)
.exchange()
.expectStatus()
.isOk()
.expectBody()
.consumeWith(document("image-upload", requestPartBody("metadata"))); (1)
}
}
| 1 | Configure Spring REST docs to produce a snippet containing the body of the request part named metadata.
Uses the static requestPartBody method on PayloadDocumentation. |
The result is a snippet named request-part-${part-name}-body.adoc that contains the part’s body.
For example, documenting a part named metadata produces a snippet named request-part-metadata-body.adoc.
Documenting a Request Part’s Fields
You can document a request part’s fields in much the same way as the fields of a request or response, as follows:
-
MockMvc
-
WebTestClient
import org.junit.jupiter.api.Test;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.multipart;
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
import static org.springframework.restdocs.payload.PayloadDocumentation.requestPartFields;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
class RequestPartFields {
// Fields
private MockMvc mockMvc;
@Test
void test() throws Exception {
MockMultipartFile image = new MockMultipartFile("image", "image.png", "image/png", "<<png data>>".getBytes());
MockMultipartFile metadata = new MockMultipartFile("metadata", "", "application/json",
"{ \"version\": \"1.0\"}".getBytes());
this.mockMvc.perform(multipart("/images").file(image).file(metadata).accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andDo(document("image-upload", requestPartFields("metadata", (1)
fieldWithPath("version").description("The version of the image")))); (2)
}
}
| 1 | Configure Spring REST docs to produce a snippet describing the fields in the payload of the request part named metadata.
Uses the static requestPartFields method on PayloadDocumentation. |
| 2 | Expect a field with the path version.
Uses the static fieldWithPath method on org.springframework.restdocs.payload.PayloadDocumentation. |
import java.util.Collections;
import org.junit.jupiter.api.Test;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.Resource;
import org.springframework.http.MediaType;
import org.springframework.test.web.reactive.server.WebTestClient;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.reactive.function.BodyInserters;
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
import static org.springframework.restdocs.payload.PayloadDocumentation.requestPartFields;
import static org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation.document;
class RequestPartFields {
// Fields
private WebTestClient webTestClient;
@Test
void test() {
MultiValueMap<String, Object> multipartData = new LinkedMultiValueMap<>();
Resource imageResource = new ByteArrayResource("<<png data>>".getBytes()) {
@Override
public String getFilename() {
return "image.png";
}
};
multipartData.add("image", imageResource);
multipartData.add("metadata", Collections.singletonMap("version", "1.0"));
this.webTestClient.post()
.uri("/images")
.body(BodyInserters.fromMultipartData(multipartData))
.accept(MediaType.APPLICATION_JSON)
.exchange()
.expectStatus()
.isOk()
.expectBody()
.consumeWith(document("image-upload", requestPartFields("metadata", (1)
fieldWithPath("version").description("The version of the image")))); (2)
}
}
| 1 | Configure Spring REST docs to produce a snippet describing the fields in the payload of the request part named metadata.
Uses the static requestPartFields method on PayloadDocumentation. |
| 2 | Expect a field with the path version.
Uses the static fieldWithPath method on org.springframework.restdocs.payload.PayloadDocumentation. |
The result is a snippet that contains a table describing the part’s fields.
This snippet is named request-part-${part-name}-fields.adoc.
For example, documenting a part named metadata produces a snippet named request-part-metadata-fields.adoc.
When documenting fields, the test fails if an undocumented field is found in the payload of the part. Similarly, the test also fails if a documented field is not found in the payload of the part and the field has not been marked as optional. For payloads with a hierarchical structure, documenting a field is sufficient for all of its descendants to also be treated as having been documented.
If you do not want to document a field, you can mark it as ignored. Doing so prevents it from appearing in the generated snippet while avoiding the failure described above.
You can also document fields in a relaxed mode, where any undocumented fields do not cause a test failure.
To do so, use the relaxedRequestPartFields method on org.springframework.restdocs.payload.PayloadDocumentation.
This can be useful when documenting a particular scenario where you only want to focus on a subset of the payload of the part.
For further information on describing fields, documenting payloads that use XML, and more, see the section on documenting request and response payloads.