Documenting your API

This section provides more details about using Spring REST Docs to document your API.spring-doc.cn

Hypermedia

Spring REST Docs provides support for documenting the links in a hypermedia-based API. The following examples show how to use it:spring-doc.cn

MockMvc
this.mockMvc.perform(get("/").accept(MediaType.APPLICATION_JSON))
	.andExpect(status().isOk())
	.andDo(document("index", links((1)
			linkWithRel("alpha").description("Link to the alpha resource"), (2)
			linkWithRel("bravo").description("Link to the bravo resource")))); (3)
1 Configure Spring REST docs to produce a snippet describing the response’s links. Uses the static links method on org.springframework.restdocs.hypermedia.HypermediaDocumentation.
2 Expect a link whose rel is alpha. Uses the static linkWithRel method on org.springframework.restdocs.hypermedia.HypermediaDocumentation.
3 Expect a link whose rel is bravo.
WebTestClient
this.webTestClient.get()
	.uri("/")
	.accept(MediaType.APPLICATION_JSON)
	.exchange()
	.expectStatus()
	.isOk()
	.expectBody()
	.consumeWith(document("index", links((1)
			linkWithRel("alpha").description("Link to the alpha resource"), (2)
			linkWithRel("bravo").description("Link to the bravo resource")))); (3)
1 Configure Spring REST docs to produce a snippet describing the response’s links. Uses the static links method on org.springframework.restdocs.hypermedia.HypermediaDocumentation.
2 Expect a link whose rel is alpha. Uses the static linkWithRel method on org.springframework.restdocs.hypermedia.HypermediaDocumentation.
3 Expect a link whose rel is bravo.
REST Assured
RestAssured.given(this.spec)
	.accept("application/json")
	.filter(document("index", links((1)
			linkWithRel("alpha").description("Link to the alpha resource"), (2)
			linkWithRel("bravo").description("Link to the bravo resource")))) (3)
	.get("/")
	.then()
	.assertThat()
	.statusCode(is(200));
1 Configure Spring REST docs to produce a snippet describing the response’s links. Uses the static links method on org.springframework.restdocs.hypermedia.HypermediaDocumentation.
2 Expect a link whose rel is alpha. Uses the static linkWithRel method on org.springframework.restdocs.hypermedia.HypermediaDocumentation.
3 Expect a link whose rel is bravo.

The result is a snippet named links.adoc that contains a table describing the resource’s links.spring-doc.cn

If a link in the response has a title, you can omit the description from its descriptor and the title is used. If you omit the description and the link does not have a title, a failure occurs.

When documenting links, the test fails if an undocumented link is found in the response. Similarly, the test also fails if a documented link is not found in the response and the link has not been marked as optional.spring-doc.cn

If you do not want to document a link, you can mark it as ignored. Doing so prevents it from appearing in the generated snippet while avoiding the failure described above.spring-doc.cn

You can also document links in a relaxed mode, where any undocumented links do not cause a test failure. To do so, use the relaxedLinks method on org.springframework.restdocs.hypermedia.HypermediaDocumentation. This can be useful when documenting a particular scenario where you only want to focus on a subset of the links.spring-doc.cn

Two link formats are understood by default:spring-doc.cn

  • Atom: Links are expected to be in an array named links. This is used by default when the content type of the response is compatible with application/json.spring-doc.cn

  • HAL: Links are expected to be in a map named _links. This is used by default when the content type of the response is compatible with application/hal+json.spring-doc.cn

If you use Atom- or HAL-format links but with a different content type, you can provide one of the built-in LinkExtractor implementations to links. The following examples show how to do so:spring-doc.cn

MockMvc
.andDo(document("index", links(halLinks(), (1)
		linkWithRel("alpha").description("Link to the alpha resource"),
		linkWithRel("bravo").description("Link to the bravo resource"))));
1 Indicate that the links are in HAL format. Uses the static halLinks method on org.springframework.restdocs.hypermedia.HypermediaDocumentation.
WebTestClient
.consumeWith(document("index", links(halLinks(), (1)
		linkWithRel("alpha").description("Link to the alpha resource"),
		linkWithRel("bravo").description("Link to the bravo resource"))));
1 Indicate that the links are in HAL format. Uses the static halLinks method on org.springframework.restdocs.hypermedia.HypermediaDocumentation.
REST Assured
.filter(document("index", links(halLinks(), (1)
		linkWithRel("alpha").description("Link to the alpha resource"),
		linkWithRel("bravo").description("Link to the bravo resource"))))
1 Indicate that the links are in HAL format. Uses the static halLinks method on org.springframework.restdocs.hypermedia.HypermediaDocumentation.

If your API represents its links in a format other than Atom or HAL, you can provide your own implementation of the LinkExtractor interface to extract the links from the response.spring-doc.cn

Rather than documenting links that are common to every response, such as self and curies when using HAL, you may want to document them once in an overview section and then ignore them in the rest of your API’s documentation. To do so, you can build on the support for reusing snippets to add link descriptors to a snippet that is preconfigured to ignore certain links. The following example shows how to do so:spring-doc.cn

public static LinksSnippet links(LinkDescriptor... descriptors) {
	return HypermediaDocumentation.links(linkWithRel("self").ignored().optional(), linkWithRel("curies").ignored())
		.and(descriptors);
}

Request and Response Payloads

In addition to the hypermedia-specific support described earlier, support for general documentation of request and response payloads is also provided.spring-doc.cn

By default, Spring REST Docs automatically generates snippets for the body of the request and the body of the response. These snippets are named request-body.adoc and response-body.adoc respectively.spring-doc.cn

Request and Response Fields

To provide more detailed documentation of a request or response payload, support for documenting the payload’s fields is provided.spring-doc.cn

Consider the following payload:spring-doc.cn

{
	"contact": {
		"name": "Jane Doe",
		"email": "[email protected]"
	}
}

You can document the previous example’s fields as follows:spring-doc.cn

MockMvc
this.mockMvc.perform(get("/user/5").accept(MediaType.APPLICATION_JSON))
	.andExpect(status().isOk())
	.andDo(document("index", responseFields((1)
			fieldWithPath("contact.email").description("The user's email address"), (2)
			fieldWithPath("contact.name").description("The user's name")))); (3)
1 Configure Spring REST docs to produce a snippet describing the fields in the response payload. To document a request, you can use requestFields. Both are static methods on org.springframework.restdocs.payload.PayloadDocumentation.
2 Expect a field with the path contact.email. Uses the static fieldWithPath method on org.springframework.restdocs.payload.PayloadDocumentation.
3 Expect a field with the path contact.name.
WebTestClient
this.webTestClient.get().uri("user/5").accept(MediaType.APPLICATION_JSON)
	.exchange().expectStatus().isOk().expectBody()
	.consumeWith(document("user",
		responseFields((1)
			fieldWithPath("contact.email").description("The user's email address"), (2)
			fieldWithPath("contact.name").description("The user's name")))); (3)
1 Configure Spring REST docs to produce a snippet describing the fields in the response payload. To document a request, you can use requestFields. Both are static methods on org.springframework.restdocs.payload.PayloadDocumentation.
2 Expect a field with the path contact.email. Uses the static fieldWithPath method on org.springframework.restdocs.payload.PayloadDocumentation.
3 Expect a field with the path contact.name.
REST Assured
RestAssured.given(this.spec)
	.accept("application/json")
	.filter(document("user", responseFields((1)
			fieldWithPath("contact.name").description("The user's name"), (2)
			fieldWithPath("contact.email").description("The user's email address")))) (3)
	.when()
	.get("/user/5")
	.then()
	.assertThat()
	.statusCode(is(200));
1 Configure Spring REST docs to produce a snippet describing the fields in the response payload. To document a request, you can use requestFields. Both are static methods on org.springframework.restdocs.payload.PayloadDocumentation.
2 Expect a field with the path contact.email. Uses the static fieldWithPath method on org.springframework.restdocs.payload.PayloadDocumentation.
3 Expect a field with the path contact.name.

The result is a snippet that contains a table describing the fields. For requests, this snippet is named request-fields.adoc. For responses, this snippet is named response-fields.adoc.spring-doc.cn

When documenting fields, the test fails if an undocumented field is found in the payload. Similarly, the test also fails if a documented field is not found in the payload and the field has not been marked as optional.spring-doc.cn

If you do not want to provide detailed documentation for all of the fields, an entire subsection of a payload can be documented. The following examples show how to do so:spring-doc.cn

MockMvc
this.mockMvc.perform(get("/user/5").accept(MediaType.APPLICATION_JSON))
	.andExpect(status().isOk())
	.andDo(document("index", responseFields((1)
			subsectionWithPath("contact").description("The user's contact details")))); (1)
1 Document the subsection with the path contact. contact.email and contact.name are now seen as having also been documented. Uses the static subsectionWithPath method on org.springframework.restdocs.payload.PayloadDocumentation.
WebTestClient
this.webTestClient.get().uri("user/5").accept(MediaType.APPLICATION_JSON)
	.exchange().expectStatus().isOk().expectBody()
	.consumeWith(document("user",
		responseFields(
			subsectionWithPath("contact").description("The user's contact details")))); (1)
1 Document the subsection with the path contact. contact.email and contact.name are now seen as having also been documented. Uses the static subsectionWithPath method on org.springframework.restdocs.payload.PayloadDocumentation.
REST Assured
RestAssured.given(this.spec)
	.accept("application/json")
	.filter(document("user",
			responseFields(subsectionWithPath("contact").description("The user's contact details")))) (1)
	.when()
	.get("/user/5")
	.then()
	.assertThat()
	.statusCode(is(200));
1 Document the subsection with the path contact. contact.email and contact.name are now seen as having also been documented. Uses the static subsectionWithPath method on org.springframework.restdocs.payload.PayloadDocumentation.

subsectionWithPath can be useful for providing a high-level overview of a particular section of a payload. You can then produce separate, more detailed documentation for a subsection. See Documenting a Subsection of a Request or Response Payload.spring-doc.cn

If you do not want to document a field or subsection at all, you can mark it as ignored. This prevents it from appearing in the generated snippet while avoiding the failure described earlier.spring-doc.cn

You can also document fields in a relaxed mode, where any undocumented fields do not cause a test failure. To do so, use the relaxedRequestFields and relaxedResponseFields methods on org.springframework.restdocs.payload.PayloadDocumentation. This can be useful when documenting a particular scenario where you want to focus only on a subset of the payload.spring-doc.cn

By default, Spring REST Docs assumes that the payload you are documenting is JSON. If you want to document an XML payload, the content type of the request or response must be compatible with application/xml.
Fields in JSON Payloads

This section describes how to work with fields in JSON payloads.spring-doc.cn

JSON Field Paths

JSON field paths use either dot notation or bracket notation. Dot notation uses '.' to separate each key in the path (for example, a.b). Bracket notation wraps each key in square brackets and single quotation marks (for example, ['a']['b']). In either case, [] is used to identify an array. Dot notation is more concise, but using bracket notation enables the use of . within a key name (for example, ['a.b']). The two different notations can be used in the same path (for example, a['b']).spring-doc.cn

Consider the following JSON payload:spring-doc.cn

{
	"a":{
		"b":[
			{
				"c":"one"
			},
			{
				"c":"two"
			},
			{
				"d":"three"
			}
		],
		"e.dot" : "four"
	}
}

In the preceding JSON payload, the following paths are all present:spring-doc.cn

Path Value

aspring-doc.cn

An object containing bspring-doc.cn

a.bspring-doc.cn

An array containing three objectsspring-doc.cn

['a']['b']spring-doc.cn

An array containing three objectsspring-doc.cn

a['b']spring-doc.cn

An array containing three objectsspring-doc.cn

['a'].bspring-doc.cn

An array containing three objectsspring-doc.cn

a.b[]spring-doc.cn

An array containing three objectsspring-doc.cn

a.b[].cspring-doc.cn

An array containing the strings one and twospring-doc.cn

a.b[].dspring-doc.cn

The string threespring-doc.cn

a['e.dot']spring-doc.cn

The string fourspring-doc.cn

['a']['e.dot']spring-doc.cn

The string fourspring-doc.cn

You can also document a payload that uses an array at its root. The path [] refers to the entire array. You can then use bracket or dot notation to identify fields within the array’s entries. For example, [].id corresponds to the id field of every object found in the following array:spring-doc.cn

[
	{
		"id":1
	},
	{
		"id":2
	}
]

You can use * as a wildcard to match fields with different names. For example, users.*.role could be used to document the role of every user in the following JSON:spring-doc.cn

{
	"users":{
		"ab12cd34":{
			"role": "Administrator"
		},
		"12ab34cd":{
			"role": "Guest"
		}
	}
}
JSON Field Types

When a field is documented, Spring REST Docs tries to determine its type by examining the payload. Seven different types are supported:spring-doc.cn

Type Description

arrayspring-doc.cn

The value of each occurrence of the field is an array.spring-doc.cn

booleanspring-doc.cn

The value of each occurrence of the field is a boolean (true or false).spring-doc.cn

objectspring-doc.cn

The value of each occurrence of the field is an object.spring-doc.cn

numberspring-doc.cn

The value of each occurrence of the field is a number.spring-doc.cn

nullspring-doc.cn

The value of each occurrence of the field is null.spring-doc.cn

stringspring-doc.cn

The value of each occurrence of the field is a string.spring-doc.cn

variesspring-doc.cn

The field occurs multiple times in the payload with a variety of different types.spring-doc.cn

You can also explicitly set the type by using the type(Object) method on FieldDescriptor. The result of the toString method of the supplied Object is used in the documentation. Typically, one of the values enumerated by JsonFieldType is used. The following examples show how to do so:spring-doc.cn

MockMvc
.andDo(document("index", responseFields(fieldWithPath("contact.email").type(JsonFieldType.STRING) (1)
	.description("The user's email address"))));
1 Set the field’s type to String.
WebTestClient
.consumeWith(document("user",
	responseFields(
		fieldWithPath("contact.email")
			.type(JsonFieldType.STRING) (1)
			.description("The user's email address"))));
1 Set the field’s type to String.
REST Assured
.filter(document("user", responseFields(fieldWithPath("contact.email").type(JsonFieldType.STRING) (1)
	.description("The user's email address"))))
1 Set the field’s type to String.
XML payloads

This section describes how to work with XML payloads.spring-doc.cn

XML Field Paths

XML field paths are described using XPath. / is used to descend into a child node.spring-doc.cn

XML Field Types

When documenting an XML payload, you must provide a type for the field by using the type(Object) method on FieldDescriptor. The result of the supplied type’s toString method is used in the documentation.spring-doc.cn

Reusing Field Descriptors

In addition to the general support for reusing snippets, the request and response snippets let additional descriptors be configured with a path prefix. This lets the descriptors for a repeated portion of a request or response payload be created once and then reused.spring-doc.cn

Consider an endpoint that returns a book:spring-doc.cn

{
	"title": "Pride and Prejudice",
	"author": "Jane Austen"
}

The paths for title and author are title and author, respectively.spring-doc.cn

Now consider an endpoint that returns an array of books:spring-doc.cn

[{
	"title": "Pride and Prejudice",
	"author": "Jane Austen"
},
{
	"title": "To Kill a Mockingbird",
	"author": "Harper Lee"
}]

The paths for title and author are [].title and [].author, respectively. The only difference between the single book and the array of books is that the fields' paths now have a []. prefix.spring-doc.cn

You can create the descriptors that document a book as follows:spring-doc.cn

FieldDescriptor[] book = new FieldDescriptor[] { fieldWithPath("title").description("Title of the book"),
		fieldWithPath("author").description("Author of the book") };

You can then use them to document a single book, as follows:spring-doc.cn

MockMvc
this.mockMvc.perform(get("/books/1").accept(MediaType.APPLICATION_JSON))
	.andExpect(status().isOk())
	.andDo(document("book", responseFields(book))); (1)
1 Document title and author by using existing descriptors
WebTestClient
this.webTestClient.get().uri("/books/1").accept(MediaType.APPLICATION_JSON)
	.exchange().expectStatus().isOk().expectBody()
	.consumeWith(document("book",
		responseFields(book))); (1)
1 Document title and author by using existing descriptors
REST Assured
RestAssured.given(this.spec)
	.accept("application/json")
	.filter(document("book", responseFields(book))) (1)
	.when()
	.get("/books/1")
	.then()
	.assertThat()
	.statusCode(is(200));
1 Document title and author by using existing descriptors

You can also use the descriptors to document an array of books, as follows:spring-doc.cn

MockMvc
this.mockMvc.perform(get("/books").accept(MediaType.APPLICATION_JSON))
	.andExpect(status().isOk())
	.andDo(document("book", responseFields(fieldWithPath("[]").description("An array of books")) (1)
		.andWithPrefix("[].", book))); (2)
1 Document the array.
2 Document [].title and [].author by using the existing descriptors prefixed with [].
WebTestClient
this.webTestClient.get().uri("/books").accept(MediaType.APPLICATION_JSON)
	.exchange().expectStatus().isOk().expectBody()
	.consumeWith(document("books",
		responseFields(
			fieldWithPath("[]")
				.description("An array of books")) (1)
				.andWithPrefix("[].", book))); (2)
1 Document the array.
2 Document [].title and [].author by using the existing descriptors prefixed with [].
REST Assured
RestAssured.given(this.spec)
	.accept("application/json")
	.filter(document("books", responseFields(fieldWithPath("[]").description("An array of books")) (1)
		.andWithPrefix("[].", book))) (2)
	.when()
	.get("/books")
	.then()
	.assertThat()
	.statusCode(is(200));
1 Document the array.
2 Document [].title and [].author by using the existing descriptors prefixed with [].

Documenting a Subsection of a Request or Response Payload

If a payload is large or structurally complex, it can be useful to document individual sections of the payload. REST Docs let you do so by extracting a subsection of the payload and then documenting it.spring-doc.cn

Documenting a Subsection of a Request or Response Body

Consider the following JSON response body:spring-doc.cn

{
	"weather": {
		"wind": {
			"speed": 15.3,
			"direction": 287.0
		},
		"temperature": {
			"high": 21.2,
			"low": 14.8
		}
	}
}

You can produce a snippet that documents the temperature object as follows:spring-doc.cn

MockMvc
this.mockMvc.perform(get("/locations/1").accept(MediaType.APPLICATION_JSON))
	.andExpect(status().isOk())
	.andDo(document("location", responseBody(beneathPath("weather.temperature")))); (1)
1 Produce a snippet containing a subsection of the response body. Uses the static responseBody and beneathPath methods on org.springframework.restdocs.payload.PayloadDocumentation. To produce a snippet for the request body, you can use requestBody in place of responseBody.
WebTestClient
this.webTestClient.get().uri("/locations/1").accept(MediaType.APPLICATION_JSON)
	.exchange().expectStatus().isOk().expectBody()
	.consumeWith(document("temperature",
		responseBody(beneathPath("weather.temperature")))); (1)
1 Produce a snippet containing a subsection of the response body. Uses the static responseBody and beneathPath methods on org.springframework.restdocs.payload.PayloadDocumentation. To produce a snippet for the request body, you can use requestBody in place of responseBody.
REST Assured
RestAssured.given(this.spec)
	.accept("application/json")
	.filter(document("location", responseBody(beneathPath("weather.temperature")))) (1)
	.when()
	.get("/locations/1")
	.then()
	.assertThat()
	.statusCode(is(200));
1 Produce a snippet containing a subsection of the response body. Uses the static responseBody and beneathPath methods on org.springframework.restdocs.payload.PayloadDocumentation. To produce a snippet for the request body, you can use requestBody in place of responseBody.

The result is a snippet with the following contents:spring-doc.cn

{
	"temperature": {
		"high": 21.2,
		"low": 14.8
	}
}

To make the snippet’s name distinct, an identifier for the subsection is included. By default, this identifier is beneath-${path}. For example, the preceding code results in a snippet named response-body-beneath-weather.temperature.adoc. You can customize the identifier by using the withSubsectionId(String) method, as follows:spring-doc.cn

responseBody(beneathPath("weather.temperature").withSubsectionId("temp"));

The result is a snippet named request-body-temp.adoc.spring-doc.cn

Documenting the Fields of a Subsection of a Request or Response

As well as documenting a subsection of a request or response body, you can also document the fields in a particular subsection. You can produce a snippet that documents the fields of the temperature object (high and low) as follows:spring-doc.cn

MockMvc
this.mockMvc.perform(get("/locations/1").accept(MediaType.APPLICATION_JSON))
	.andExpect(status().isOk())
	.andDo(document("location", responseFields(beneathPath("weather.temperature"), (1)
			fieldWithPath("high").description("The forecast high in degrees celcius"), (2)
			fieldWithPath("low").description("The forecast low in degrees celcius"))));
1 Produce a snippet describing the fields in the subsection of the response payload beneath the path weather.temperature. Uses the static beneathPath method on org.springframework.restdocs.payload.PayloadDocumentation.
2 Document the high and low fields.
WebTestClient
this.webTestClient.get().uri("/locations/1").accept(MediaType.APPLICATION_JSON)
	.exchange().expectStatus().isOk().expectBody()
	.consumeWith(document("temperature",
		responseFields(beneathPath("weather.temperature"), (1)
			fieldWithPath("high").description("The forecast high in degrees celcius"), (2)
			fieldWithPath("low").description("The forecast low in degrees celcius"))));
1 Produce a snippet describing the fields in the subsection of the response payload beneath the path weather.temperature. Uses the static beneathPath method on org.springframework.restdocs.payload.PayloadDocumentation.
2 Document the high and low fields.
REST Assured
RestAssured.given(this.spec)
	.accept("application/json")
	.filter(document("location", responseFields(beneathPath("weather.temperature"), (1)
			fieldWithPath("high").description("The forecast high in degrees celcius"), (2)
			fieldWithPath("low").description("The forecast low in degrees celcius"))))
	.when()
	.get("/locations/1")
	.then()
	.assertThat()
	.statusCode(is(200));
1 Produce a snippet describing the fields in the subsection of the response payload beneath the path weather.temperature. Uses the static beneathPath method on org.springframework.restdocs.payload.PayloadDocumentation.
2 Document the high and low fields.

The result is a snippet that contains a table describing the high and low fields of weather.temperature. To make the snippet’s name distinct, an identifier for the subsection is included. By default, this identifier is beneath-${path}. For example, the preceding code results in a snippet named response-fields-beneath-weather.temperature.adoc.spring-doc.cn

Query Parameters

You can document a request’s query parameters by using queryParameters. The following examples show how to do so:spring-doc.cn

MockMvc
this.mockMvc.perform(get("/users?page=2&per_page=100")) (1)
	.andExpect(status().isOk())
	.andDo(document("users", queryParameters((2)
			parameterWithName("page").description("The page to retrieve"), (3)
			parameterWithName("per_page").description("Entries per page") (4)
	)));
1 Perform a GET request with two parameters, page and per_page, in the query string. Query parameters should be included in the URL, as shown here, or specified using the request builder’s queryParam or queryParams method. The param and params methods should be avoided as the source of the parameters is then ambiguous.
2 Configure Spring REST Docs to produce a snippet describing the request’s query parameters. Uses the static queryParameters method on org.springframework.restdocs.request.RequestDocumentation.
3 Document the page query parameter. Uses the static parameterWithName method on org.springframework.restdocs.request.RequestDocumentation.
4 Document the per_page query parameter.
WebTestClient
this.webTestClient.get().uri("/users?page=2&per_page=100") (1)
	.exchange().expectStatus().isOk().expectBody()
	.consumeWith(document("users", queryParameters((2)
			parameterWithName("page").description("The page to retrieve"), (3)
			parameterWithName("per_page").description("Entries per page") (4)
	)));
1 Perform a GET request with two parameters, page and per_page, in the query string.
2 Configure Spring REST Docs to produce a snippet describing the request’s query parameters. Uses the static queryParameters method on org.springframework.restdocs.request.RequestDocumentation.
3 Document the page parameter. Uses the static parameterWithName method on org.springframework.restdocs.request.RequestDocumentation.
4 Document the per_page parameter.
REST Assured
RestAssured.given(this.spec)
	.filter(document("users", queryParameters((1)
			parameterWithName("page").description("The page to retrieve"), (2)
			parameterWithName("per_page").description("Entries per page")))) (3)
	.when()
	.get("/users?page=2&per_page=100") (4)
	.then()
	.assertThat()
	.statusCode(is(200));
1 Configure Spring REST Docs to produce a snippet describing the request’s query parameters. Uses the static queryParameters method on org.springframework.restdocs.request.RequestDocumentation.
2 Document the page parameter. Uses the static parameterWithName method on org.springframework.restdocs.request.RequestDocumentation.
3 Document the per_page parameter.
4 Perform a GET request with two parameters, page and per_page, in the query string.

When documenting query parameters, the test fails if an undocumented query parameter is used in the request’s query string. Similarly, the test also fails if a documented query parameter is not found in the request’s query string and the parameter has not been marked as optional.spring-doc.cn

If you do not want to document a query parameter, you can mark it as ignored. This prevents it from appearing in the generated snippet while avoiding the failure described above.spring-doc.cn

You can also document query parameters in a relaxed mode where any undocumented parameters do not cause a test failure. To do so, use the relaxedQueryParameters 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 query parameters.spring-doc.cn

Form Parameters

You can document a request’s form parameters by using formParameters. The following examples show how to do so:spring-doc.cn

MockMvc
this.mockMvc.perform(post("/users").param("username", "Tester")) (1)
	.andExpect(status().isCreated())
	.andDo(document("create-user", formParameters((2)
			parameterWithName("username").description("The user's username") (3)
	)));
1 Perform a POST request with a single form parameter, username.
2 Configure Spring REST Docs to produce a snippet describing the request’s form parameters. Uses the static formParameters method on org.springframework.restdocs.request.RequestDocumentation.
3 Document the username parameter. Uses the static parameterWithName method on org.springframework.restdocs.request.RequestDocumentation.
WebTestClient
MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
formData.add("username", "Tester");
this.webTestClient.post().uri("/users").body(BodyInserters.fromFormData(formData)) (1)
		.exchange().expectStatus().isCreated().expectBody()
		.consumeWith(document("create-user", formParameters((2)
				parameterWithName("username").description("The user's username") (3)
		)));
1 Perform a POST request with a single form parameter, username.
2 Configure Spring REST Docs to produce a snippet describing the request’s form parameters. Uses the static formParameters method on org.springframework.restdocs.request.RequestDocumentation.
3 Document the username parameter. Uses the static parameterWithName method on org.springframework.restdocs.request.RequestDocumentation.
REST Assured
RestAssured.given(this.spec)
	.filter(document("create-user", formParameters((1)
			parameterWithName("username").description("The user's username")))) (2)
	.formParam("username", "Tester")
	.when()
	.post("/users") (3)
	.then()
	.assertThat()
	.statusCode(is(200));
1 Configure Spring REST Docs to produce a snippet describing the request’s form parameters. Uses the static formParameters method on org.springframework.restdocs.request.RequestDocumentation.
2 Document the username parameter. Uses the static parameterWithName method on org.springframework.restdocs.request.RequestDocumentation.
3 Perform a POST request with a single form parameter, username.

In all cases, the result is a snippet named form-parameters.adoc that contains a table describing the form parameters that are supported by the resource.spring-doc.cn

When documenting form parameters, the test fails if an undocumented form parameter is used in the request body. Similarly, the test also fails if a documented form parameter is not found in the request body and the form parameter has not been marked as optional.spring-doc.cn

If you do not want to document a form parameter, you can mark it as ignored. This prevents it from appearing in the generated snippet while avoiding the failure described above.spring-doc.cn

You can also document form parameters in a relaxed mode where any undocumented parameters do not cause a test failure. To do so, use the relaxedFormParameters 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 form parameters.spring-doc.cn

Path Parameters

You can document a request’s path parameters by using pathParameters. The following examples show how to do so:spring-doc.cn

MockMvc
this.mockMvc.perform(get("/locations/{latitude}/{longitude}", 51.5072, 0.1275)) (1)
	.andExpect(status().isOk())
	.andDo(document("locations", pathParameters((2)
			parameterWithName("latitude").description("The location's latitude"), (3)
			parameterWithName("longitude").description("The location's longitude") (4)
	)));
1 Perform a GET request with two path parameters, latitude and longitude.
2 Configure Spring REST Docs to produce a snippet describing the request’s path parameters. Uses the static pathParameters method on org.springframework.restdocs.request.RequestDocumentation.
3 Document the parameter named latitude. Uses the static parameterWithName method on org.springframework.restdocs.request.RequestDocumentation.
4 Document the parameter named longitude.
WebTestClient
this.webTestClient.get().uri("/locations/{latitude}/{longitude}", 51.5072, 0.1275) (1)
	.exchange().expectStatus().isOk().expectBody()
	.consumeWith(document("locations",
		pathParameters((2)
			parameterWithName("latitude").description("The location's latitude"), (3)
			parameterWithName("longitude").description("The location's longitude")))); (4)
1 Perform a GET request with two path parameters, latitude and longitude.
2 Configure Spring REST Docs to produce a snippet describing the request’s path parameters. Uses the static pathParameters method on org.springframework.restdocs.request.RequestDocumentation.
3 Document the parameter named latitude. Uses the static parameterWithName method on org.springframework.restdocs.request.RequestDocumentation.
4 Document the parameter named longitude.
REST Assured
RestAssured.given(this.spec)
	.filter(document("locations", pathParameters((1)
			parameterWithName("latitude").description("The location's latitude"), (2)
			parameterWithName("longitude").description("The location's longitude")))) (3)
	.when()
	.get("/locations/{latitude}/{longitude}", 51.5072, 0.1275) (4)
	.then()
	.assertThat()
	.statusCode(is(200));
1 Configure Spring REST Docs to produce a snippet describing the request’s path parameters. Uses the static pathParameters method on org.springframework.restdocs.request.RequestDocumentation.
2 Document the parameter named latitude. Uses the static parameterWithName method on org.springframework.restdocs.request.RequestDocumentation.
3 Document the parameter named longitude.
4 Perform a GET request with two path parameters, latitude and longitude.

The result is a snippet named path-parameters.adoc that contains a table describing the path parameters that are supported by the resource.spring-doc.cn

If you use MockMvc with Spring Framework 6.1 or earlier, to make the path parameters available for documentation, you must build the request by using one of the methods on RestDocumentationRequestBuilders rather than MockMvcRequestBuilders.

When documenting path parameters, the test fails if an undocumented path parameter is used in the request. Similarly, the test also fails if a documented path parameter is not found in the request and the path parameter has not been marked as optional.spring-doc.cn

You can also document path parameters in a relaxed mode, where any undocumented parameters do not cause a test failure. To do so, use the relaxedPathParameters 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 path parameters.spring-doc.cn

If you do not want to document a path parameter, you can mark it as ignored. Doing so prevents it from appearing in the generated snippet while avoiding the failure described earlier.spring-doc.cn

Request Parts

You can use requestParts to document the parts of a multipart request. The following example shows how to do so:spring-doc.cn

MockMvc
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.
WebTestClient
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.
REST Assured
RestAssured.given(this.spec)
	.filter(document("users", requestParts((1)
			partWithName("file").description("The file to upload")))) (2)
	.multiPart("file", "example") (3)
	.when()
	.post("/upload") (4)
	.then()
	.statusCode(is(200));
1 Configure Spring REST Docs to produce a snippet describing the request’s parts. Uses the static requestParts method on org.springframework.restdocs.request.RequestDocumentation.
2 Document the part named file. Uses the static partWithName method on org.springframework.restdocs.request.RequestDocumentation.
3 Configure the request with the part named file.
4 Perform the POST request to /upload.

The result is a snippet named request-parts.adoc that contains a table describing the request parts that are supported by the resource.spring-doc.cn

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.spring-doc.cn

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.spring-doc.cn

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.spring-doc.cn

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.spring-doc.cn

Documenting a Request Part’s Body

You can generate a snippet containing the body of a request part as follows:spring-doc.cn

MockMvc
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.
WebTestClient
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.
REST Assured
Map<String, String> metadata = new HashMap<>();
metadata.put("version", "1.0");
RestAssured.given(this.spec)
	.accept("application/json")
	.filter(document("image-upload", requestPartBody("metadata"))) (1)
	.when()
	.multiPart("image", new File("image.png"), "image/png")
	.multiPart("metadata", metadata)
	.post("images")
	.then()
	.assertThat()
	.statusCode(is(200));
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.spring-doc.cn

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:spring-doc.cn

MockMvc
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.
WebTestClient
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.
REST Assured
Map<String, String> metadata = new HashMap<>();
metadata.put("version", "1.0");
RestAssured.given(this.spec)
	.accept("application/json")
	.filter(document("image-upload", requestPartFields("metadata", (1)
			fieldWithPath("version").description("The version of the image")))) (2)
	.when()
	.multiPart("image", new File("image.png"), "image/png")
	.multiPart("metadata", metadata)
	.post("images")
	.then()
	.assertThat()
	.statusCode(is(200));
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.spring-doc.cn

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.spring-doc.cn

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.spring-doc.cn

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.spring-doc.cn

For further information on describing fields, documenting payloads that use XML, and more, see the section on documenting request and response payloads.spring-doc.cn

HTTP Headers

You can document the headers in a request or response by using requestHeaders and responseHeaders, respectively. The following examples show how to do so:spring-doc.cn

MockMvc
this.mockMvc.perform(get("/people").header("Authorization", "Basic dXNlcjpzZWNyZXQ=")) (1)
	.andExpect(status().isOk())
	.andDo(document("headers", requestHeaders((2)
			headerWithName("Authorization").description("Basic auth credentials")), (3)
			responseHeaders((4)
					headerWithName("X-RateLimit-Limit")
						.description("The total number of requests permitted per period"),
					headerWithName("X-RateLimit-Remaining")
						.description("Remaining requests permitted in current period"),
					headerWithName("X-RateLimit-Reset")
						.description("Time at which the rate limit period will reset"))));
1 Perform a GET request with an Authorization header that uses basic authentication.
2 Configure Spring REST Docs to produce a snippet describing the request’s headers. Uses the static requestHeaders method on org.springframework.restdocs.headers.HeaderDocumentation.
3 Document the Authorization header. Uses the static headerWithName method on org.springframework.restdocs.headers.HeaderDocumentation.
4 Produce a snippet describing the response’s headers. Uses the static responseHeaders method on org.springframework.restdocs.headers.HeaderDocumentation.
WebTestClient
this.webTestClient
	.get().uri("/people").header("Authorization", "Basic dXNlcjpzZWNyZXQ=") (1)
	.exchange().expectStatus().isOk().expectBody()
	.consumeWith(document("headers",
		requestHeaders((2)
			headerWithName("Authorization").description("Basic auth credentials")), (3)
		responseHeaders((4)
			headerWithName("X-RateLimit-Limit")
				.description("The total number of requests permitted per period"),
			headerWithName("X-RateLimit-Remaining")
				.description("Remaining requests permitted in current period"),
			headerWithName("X-RateLimit-Reset")
				.description("Time at which the rate limit period will reset"))));
1 Perform a GET request with an Authorization header that uses basic authentication.
2 Configure Spring REST Docs to produce a snippet describing the request’s headers. Uses the static requestHeaders method on org.springframework.restdocs.headers.HeaderDocumentation.
3 Document the Authorization header. Uses the static headerWithName method on org.springframework.restdocs.headers.HeaderDocumentation.
4 Produce a snippet describing the response’s headers. Uses the static responseHeaders method on org.springframework.restdocs.headers.HeaderDocumentation.
REST Assured
RestAssured.given(this.spec)
	.filter(document("headers", requestHeaders((1)
			headerWithName("Authorization").description("Basic auth credentials")), (2)
			responseHeaders((3)
					headerWithName("X-RateLimit-Limit")
						.description("The total number of requests permitted per period"),
					headerWithName("X-RateLimit-Remaining")
						.description("Remaining requests permitted in current period"),
					headerWithName("X-RateLimit-Reset")
						.description("Time at which the rate limit period will reset"))))
	.header("Authorization", "Basic dXNlcjpzZWNyZXQ=") (4)
	.when()
	.get("/people")
	.then()
	.assertThat()
	.statusCode(is(200));
1 Configure Spring REST Docs to produce a snippet describing the request’s headers. Uses the static requestHeaders method on org.springframework.restdocs.headers.HeaderDocumentation.
2 Document the Authorization header. Uses the static headerWithName method on `org.springframework.restdocs.headers.HeaderDocumentation.
3 Produce a snippet describing the response’s headers. Uses the static responseHeaders method on org.springframework.restdocs.headers.HeaderDocumentation.
4 Configure the request with an Authorization header that uses basic authentication.

The result is a snippet named request-headers.adoc and a snippet named response-headers.adoc. Each contains a table describing the headers.spring-doc.cn

When documenting HTTP Headers, the test fails if a documented header is not found in the request or response.spring-doc.cn

HTTP Cookies

You can document the cookies in a request or response by using requestCookies and responseCookies, respectively. The following examples show how to do so:spring-doc.cn

MockMvc
this.mockMvc.perform(get("/").cookie(new Cookie("JSESSIONID", "ACBCDFD0FF93D5BB"))) (1)
	.andExpect(status().isOk())
	.andDo(document("cookies", requestCookies((2)
			cookieWithName("JSESSIONID").description("Session token")), (3)
			responseCookies((4)
					cookieWithName("JSESSIONID").description("Updated session token"),
					cookieWithName("logged_in")
						.description("Set to true if the user is currently logged in"))));
1 Make a GET request with a JSESSIONID cookie.
2 Configure Spring REST Docs to produce a snippet describing the request’s cookies. Uses the static requestCookies method on org.springframework.restdocs.cookies.CookieDocumentation.
3 Document the JSESSIONID cookie. Uses the static cookieWithName method on org.springframework.restdocs.cookies.CookieDocumentation.
4 Produce a snippet describing the response’s cookies. Uses the static responseCookies method on org.springframework.restdocs.cookies.CookieDocumentation.
WebTestClient
this.webTestClient.get()
	.uri("/people")
	.cookie("JSESSIONID", "ACBCDFD0FF93D5BB=") (1)
	.exchange()
	.expectStatus()
	.isOk()
	.expectBody()
	.consumeWith(document("cookies", requestCookies((2)
			cookieWithName("JSESSIONID").description("Session token")), (3)
			responseCookies((4)
					cookieWithName("JSESSIONID").description("Updated session token"),
					cookieWithName("logged_in").description("User is logged in"))));
1 Make a GET request with a JSESSIONID cookie.
2 Configure Spring REST Docs to produce a snippet describing the request’s cookies. Uses the static requestCookies method on org.springframework.restdocs.cookies.CookieDocumentation.
3 Document the JSESSIONID cookie. Uses the static cookieWithName method on org.springframework.restdocs.cookies.CookieDocumentation.
4 Produce a snippet describing the response’s cookies. Uses the static responseCookies method on org.springframework.restdocs.cookies.CookieDocumentation.
REST Assured
RestAssured.given(this.spec)
	.filter(document("cookies", requestCookies((1)
			cookieWithName("JSESSIONID").description("Saved session token")), (2)
			responseCookies((3)
					cookieWithName("logged_in").description("If user is logged in"),
					cookieWithName("JSESSIONID").description("Updated session token"))))
	.cookie("JSESSIONID", "ACBCDFD0FF93D5BB") (4)
	.when()
	.get("/people")
	.then()
	.assertThat()
	.statusCode(is(200));
1 Configure Spring REST Docs to produce a snippet describing the request’s cookies. Uses the static requestCookies method on org.springframework.restdocs.cookies.CookieDocumentation.
2 Document the JSESSIONID cookie. Uses the static cookieWithName method on org.springframework.restdocs.cookies.CookieDocumentation.
3 Produce a snippet describing the response’s cookies. Uses the static responseCookies method on org.springframework.restdocs.cookies.CookieDocumentation.
4 Send a JSESSIONID cookie with the request.

The result is a snippet named request-cookies.adoc and a snippet named response-cookies.adoc. Each contains a table describing the cookies.spring-doc.cn

When documenting HTTP cookies, the test fails if an undocumented cookie is found in the request or response. Similarly, the test also fails if a documented cookie is not found and the cookie has not been marked as optional. You can also document cookies in a relaxed mode, where any undocumented cookies do not cause a test failure. To do so, use the relaxedRequestCookies and relaxedResponseCookies methods on org.springframework.restdocs.cookies.CookieDocumentation. This can be useful when documenting a particular scenario where you only want to focus on a subset of the cookies. If you do not want to document a cookie, you can mark it as ignored. Doing so prevents it from appearing in the generated snippet while avoiding the failure described earlier.spring-doc.cn

Reusing Snippets

It is common for an API that is being documented to have some features that are common across several of its resources. To avoid repetition when documenting such resources, you can reuse a Snippet configured with the common elements.spring-doc.cn

First, create the Snippet that describes the common elements. The following example shows how to do so:spring-doc.cn

protected final LinksSnippet pagingLinks = links(
		linkWithRel("first").optional().description("The first page of results"),
		linkWithRel("last").optional().description("The last page of results"),
		linkWithRel("next").optional().description("The next page of results"),
		linkWithRel("prev").optional().description("The previous page of results"));

Second, use this snippet and add further descriptors that are resource-specific. The following examples show how to do so:spring-doc.cn

MockMvc
this.mockMvc.perform(get("/").accept(MediaType.APPLICATION_JSON))
	.andExpect(status().isOk())
	.andDo(document("example", this.pagingLinks.and((1)
			linkWithRel("alpha").description("Link to the alpha resource"),
			linkWithRel("bravo").description("Link to the bravo resource"))));
1 Reuse the pagingLinks Snippet, calling and to add descriptors that are specific to the resource that is being documented.
WebTestClient
this.webTestClient.get().uri("/").accept(MediaType.APPLICATION_JSON).exchange()
	.expectStatus().isOk().expectBody()
	.consumeWith(document("example", this.pagingLinks.and((1)
		linkWithRel("alpha").description("Link to the alpha resource"),
		linkWithRel("bravo").description("Link to the bravo resource"))));
1 Reuse the pagingLinks Snippet, calling and to add descriptors that are specific to the resource that is being documented.
REST Assured
RestAssured.given(this.spec)
	.accept("application/json")
	.filter(document("example", this.pagingLinks.and((1)
			linkWithRel("alpha").description("Link to the alpha resource"),
			linkWithRel("bravo").description("Link to the bravo resource"))))
	.get("/")
	.then()
	.assertThat()
	.statusCode(is(200));
1 Reuse the pagingLinks Snippet, calling and to add descriptors that are specific to the resource that is being documented.

The result of the example is that links with rel values of first, last, next, previous, alpha, and bravo are all documented.spring-doc.cn

Documenting Constraints

Spring REST Docs provides a number of classes that can help you to document constraints. You can use an instance of ConstraintDescriptions to access descriptions of a class’s constraints. The following example shows how to do so:spring-doc.cn

public void example() {
	ConstraintDescriptions userConstraints = new ConstraintDescriptions(UserInput.class); (1)
	List<String> descriptions = userConstraints.descriptionsForProperty("name"); (2)
}

static class UserInput {

	@NotNull
	@Size(min = 1)
	String name;

	@NotNull
	@Size(min = 8)
	String password;

}
1 Create an instance of ConstraintDescriptions for the UserInput class.
2 Get the descriptions of the name property’s constraints. This list contains two descriptions: one for the NotNull constraint and one for the Size constraint.

The ApiDocumentation class in the Spring HATEOAS sample shows this functionality in action.spring-doc.cn

Finding Constraints

By default, constraints are found by using a Bean Validation Validator. Currently, only property constraints are supported. You can customize the Validator that is used by creating ConstraintDescriptions with a custom ValidatorConstraintResolver instance. To take complete control of constraint resolution, you can use your own implementation of ConstraintResolver.spring-doc.cn

Describing Constraints

Default descriptions are provided for all of Bean Validation 3.0’s constraints:spring-doc.cn

Default descriptions are also provided for the following constraints from Hibernate Validator:spring-doc.cn

To override the default descriptions or to provide a new description, you can create a resource bundle with a base name of org.springframework.restdocs.constraints.ConstraintDescriptions. The Spring HATEOAS-based sample contains an example of such a resource bundle.spring-doc.cn

Each key in the resource bundle is the fully-qualified name of a constraint plus a .description. For example, the key for the standard @NotNull constraint is jakarta.validation.constraints.NotNull.description.spring-doc.cn

You can use a property placeholder referring to a constraint’s attributes in its description. For example, the default description of the @Min constraint, Must be at least ${value}, refers to the constraint’s value attribute.spring-doc.cn

To take more control of constraint description resolution, you can create ConstraintDescriptions with a custom ResourceBundleConstraintDescriptionResolver. To take complete control, you can create ConstraintDescriptions with a custom ConstraintDescriptionResolver implementation.spring-doc.cn

Using Constraint Descriptions in Generated Snippets

Once you have a constraint’s descriptions, you are free to use them however you like in the generated snippets. For example, you may want to include the constraint descriptions as part of a field’s description. Alternatively, you could include the constraints as extra information in the request fields snippet. The ApiDocumentation class in the Spring HATEOAS-based sample illustrates the latter approach.spring-doc.cn

Default Snippets

A number of snippets are produced automatically when you document a request and response.spring-doc.cn

Snippet Description

curl-request.adocspring-doc.cn

Contains the curl command that is equivalent to the MockMvc call that is being documented.spring-doc.cn

httpie-request.adocspring-doc.cn

Contains the HTTPie command that is equivalent to the MockMvc call that is being documented.spring-doc.cn

http-request.adocspring-doc.cn

Contains the HTTP request that is equivalent to the MockMvc call that is being documented.spring-doc.cn

http-response.adocspring-doc.cn

Contains the HTTP response that was returned.spring-doc.cn

request-body.adocspring-doc.cn

Contains the body of the request that was sent.spring-doc.cn

response-body.adocspring-doc.cn

Contains the body of the response that was returned.spring-doc.cn

You can configure which snippets are produced by default. See the configuration section for more information.spring-doc.cn

Using Parameterized Output Directories

You can parameterize the output directory used by document. The following parameters are supported:spring-doc.cn

Parameter Description

{methodName}spring-doc.cn

The unmodified name of the test method.spring-doc.cn

{method-name}spring-doc.cn

The name of the test method, formatted using kebab-case.spring-doc.cn

{method_name}spring-doc.cn

The name of the test method, formatted using snake_case.spring-doc.cn

{ClassName}spring-doc.cn

The unmodified simple name of the test class.spring-doc.cn

{class-name}spring-doc.cn

The simple name of the test class, formatted using kebab-case.spring-doc.cn

{class_name}spring-doc.cn

The simple name of the test class, formatted using snake_case.spring-doc.cn

{step}spring-doc.cn

The count of calls made to the service in the current test.spring-doc.cn

For example, document("{class-name}/{method-name}") in a test method named creatingANote on the test class GettingStartedDocumentation writes snippets into a directory named getting-started-documentation/creating-a-note.spring-doc.cn

A parameterized output directory is particularly useful in combination with a @Before method. It lets documentation be configured once in a setup method and then reused in every test in the class. The following examples show how to do so:spring-doc.cn

MockMvc
@Before
public void setUp() {
	this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
		.apply(documentationConfiguration(this.restDocumentation))
		.alwaysDo(document("{method-name}/{step}/"))
		.build();
}
REST Assured
@Before
public void setUp() {
	this.spec = new RequestSpecBuilder().addFilter(documentationConfiguration(this.restDocumentation))
		.addFilter(document("{method-name}/{step}"))
		.build();
}
WebTestClient
@Before
public void setUp() {
	this.webTestClient = WebTestClient.bindToApplicationContext(this.context)
		.configureClient()
		.filter(documentationConfiguration(this.restDocumentation))
		.entityExchangeResultConsumer(document("{method-name}/{step}"))
		.build();
}

With this configuration in place, every call to the service you are testing produces the default snippets without any further configuration. Take a look at the GettingStartedDocumentation classes in each of the sample applications to see this functionality in action.spring-doc.cn

Customizing the Output

This section describes how to customize the output of Spring REST Docs.spring-doc.cn

Customizing the Generated Snippets

Spring REST Docs uses Mustache templates to produce the generated snippets. Default templates are provided for each of the snippets that Spring REST Docs can produce. To customize a snippet’s content, you can provide your own template.spring-doc.cn

Templates are loaded from the classpath from an org.springframework.restdocs.templates subpackage. The name of the subpackage is determined by the ID of the template format that is in use. The default template format, Asciidoctor, has an ID of asciidoctor, so snippets are loaded from org.springframework.restdocs.templates.asciidoctor. Each template is named after the snippet that it produces. For example, to override the template for the curl-request.adoc snippet, create a template named curl-request.snippet in src/test/resources/org/springframework/restdocs/templates/asciidoctor.spring-doc.cn

Including Extra Information

There are two ways to provide extra information for inclusion in a generated snippet:spring-doc.cn

  • Use the attributes method on a descriptor to add one or more attributes to it.spring-doc.cn

  • Pass in some attributes when calling curlRequest, httpRequest, httpResponse, and so on. Such attributes are associated with the snippet as a whole.spring-doc.cn

Any additional attributes are made available during the template rendering process. Coupled with a custom snippet template, this makes it possible to include extra information in a generated snippet.spring-doc.cn

A concrete example is the addition of a constraints column and a title when documenting request fields. The first step is to provide a constraints attribute for each field that you document and to provide a title attribute. The following examples show how to do so:spring-doc.cn

MockMvc
.andDo(document("create-user", requestFields(attributes(key("title").value("Fields for user creation")), (1)
		fieldWithPath("name").description("The user's name")
			.attributes(key("constraints").value("Must not be null. Must not be empty")), (2)
		fieldWithPath("email").description("The user's email address")
			.attributes(key("constraints").value("Must be a valid email address"))))); (3)
1 Configure the title attribute for the request fields snippet.
2 Set the constraints attribute for the name field.
3 Set the constraints attribute for the email field.
WebTestClient
.consumeWith(document("create-user",
	requestFields(
		attributes(key("title").value("Fields for user creation")), (1)
		fieldWithPath("name")
			.description("The user's name")
			.attributes(key("constraints").value("Must not be null. Must not be empty")), (2)
		fieldWithPath("email")
			.description("The user's email address")
			.attributes(key("constraints").value("Must be a valid email address"))))); (3)
1 Configure the title attribute for the request fields snippet.
2 Set the constraints attribute for the name field.
3 Set the constraints attribute for the email field.
REST Assured
.filter(document("create-user", requestFields(attributes(key("title").value("Fields for user creation")), (1)
		fieldWithPath("name").description("The user's name")
			.attributes(key("constraints").value("Must not be null. Must not be empty")), (2)
		fieldWithPath("email").description("The user's email address")
			.attributes(key("constraints").value("Must be a valid email address"))))) (3)
1 Configure the title attribute for the request fields snippet.
2 Set the constraints attribute for the name field.
3 Set the constraints attribute for the email field.

The second step is to provide a custom template named request-fields.snippet that includes the information about the fields' constraints in the generated snippet’s table and adds a title.spring-doc.cn

.{{title}} (1)
|===
|Path|Type|Description|Constraints (2)

{{#fields}}
|{{path}}
|{{type}}
|{{description}}
|{{constraints}} (3)

{{/fields}}
|===
1 Add a title to the table.
2 Add a new column named "Constraints".
3 Include the descriptors' constraints attribute in each row of the table.