Add support for documenting a portion of a request or response payload
Closes gh-312
This commit is contained in:
@@ -402,6 +402,69 @@ include::{examples-dir}/com/example/restassured/Payload.java[tags=book-array]
|
||||
<1> Document the array
|
||||
<2> Document `[].title` and `[].author` using the existing descriptors prefixed with `[].`
|
||||
|
||||
[[documenting-your-api-request-response-payloads-subsections]]
|
||||
==== Documenting a portion 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 allows you to do so by extracting a
|
||||
subsection of the payload and then documenting it.
|
||||
|
||||
Consider the following JSON response payload:
|
||||
|
||||
[source,json,indent=0]
|
||||
----
|
||||
{
|
||||
"weather": {
|
||||
"wind": {
|
||||
"speed": 15.3,
|
||||
"direction": 287.0
|
||||
},
|
||||
"temperature": {
|
||||
"high": 21.2,
|
||||
"low": 14.8
|
||||
}
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
A snippet that documents the fields of the `temperature` object (`high` and `low`) can
|
||||
be produced as follows:
|
||||
|
||||
[source,java,indent=0,role="primary"]
|
||||
.MockMvc
|
||||
----
|
||||
include::{examples-dir}/com/example/mockmvc/Payload.java[tags=subsection]
|
||||
----
|
||||
<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.
|
||||
|
||||
[source,java,indent=0,role="secondary"]
|
||||
.REST Assured
|
||||
----
|
||||
include::{examples-dir}/com/example/restassured/Payload.java[tags=subsection]
|
||||
----
|
||||
<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 code above will result in a snippet named
|
||||
`response-fields-beneath-weather.temperature.adoc`. The identifier can be customized using
|
||||
the `withSubsectionId(String)` method:
|
||||
|
||||
----
|
||||
include::{examples-dir}/com/example/Payload.java[tags=custom-subsection-id]
|
||||
----
|
||||
|
||||
This example will result in a snippet named `response-fields-temp.adoc`.
|
||||
|
||||
|
||||
|
||||
[[documenting-your-api-request-parameters]]
|
||||
=== Request parameters
|
||||
|
||||
|
||||
@@ -18,7 +18,9 @@ package com.example;
|
||||
|
||||
import org.springframework.restdocs.payload.FieldDescriptor;
|
||||
|
||||
import static org.springframework.restdocs.payload.PayloadDocumentation.beneathPath;
|
||||
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
|
||||
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
|
||||
|
||||
public class Payload {
|
||||
|
||||
@@ -31,4 +33,12 @@ public class Payload {
|
||||
// end::book-descriptors[]
|
||||
}
|
||||
|
||||
public void customSubsectionId() {
|
||||
// tag::custom-subsection-id[]
|
||||
responseFields(beneathPath("weather.temperature").withSubsectionId("temp"),
|
||||
fieldWithPath("high").description("…"),
|
||||
fieldWithPath("low").description("…"));
|
||||
// end::custom-subsection-id[]
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,21 +16,22 @@
|
||||
|
||||
package com.example.mockmvc;
|
||||
|
||||
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
|
||||
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get;
|
||||
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post;
|
||||
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
|
||||
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
|
||||
import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields;
|
||||
import static org.springframework.restdocs.snippet.Attributes.attributes;
|
||||
import static org.springframework.restdocs.snippet.Attributes.key;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.restdocs.payload.FieldDescriptor;
|
||||
import org.springframework.restdocs.payload.JsonFieldType;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
|
||||
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
|
||||
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get;
|
||||
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post;
|
||||
import static org.springframework.restdocs.payload.PayloadDocumentation.beneathPath;
|
||||
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
|
||||
import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields;
|
||||
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
|
||||
import static org.springframework.restdocs.snippet.Attributes.attributes;
|
||||
import static org.springframework.restdocs.snippet.Attributes.key;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
public class Payload {
|
||||
|
||||
private MockMvc mockMvc;
|
||||
@@ -91,4 +92,14 @@ public class Payload {
|
||||
// end::book-array[]
|
||||
}
|
||||
|
||||
public void subsection() throws Exception {
|
||||
// tag::subsection[]
|
||||
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"))));
|
||||
// end::subsection[]
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import com.jayway.restassured.RestAssured;
|
||||
import com.jayway.restassured.specification.RequestSpecification;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.springframework.restdocs.payload.PayloadDocumentation.beneathPath;
|
||||
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
|
||||
import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields;
|
||||
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
|
||||
@@ -95,4 +96,15 @@ public class Payload {
|
||||
// end::book-array[]
|
||||
}
|
||||
|
||||
public void subsection() throws Exception {
|
||||
// tag::subsection[]
|
||||
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));
|
||||
// end::subsection[]
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -45,6 +45,8 @@ public abstract class AbstractFieldsSnippet extends TemplatedSnippet {
|
||||
|
||||
private final String type;
|
||||
|
||||
private final PayloadSubsectionExtractor<?> subsectionExtractor;
|
||||
|
||||
/**
|
||||
* Creates a new {@code AbstractFieldsSnippet} that will produce a snippet named
|
||||
* {@code <type>-fields}. The fields will be documented using the given
|
||||
@@ -81,6 +83,29 @@ public abstract class AbstractFieldsSnippet extends TemplatedSnippet {
|
||||
this(type, type, descriptors, attributes, ignoreUndocumentedFields);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@code AbstractFieldsSnippet} that will produce a snippet named
|
||||
* {@code <type>-fields} using a template named {@code <type>-fields}. The fields in
|
||||
* the subsection of the payload extracted by the given {@code subsectionExtractor}
|
||||
* will be documented using the given {@code descriptors} and the given
|
||||
* {@code attributes} will be included in the model during template rendering. If
|
||||
* {@code ignoreUndocumentedFields} is {@code true}, undocumented fields will be
|
||||
* ignored and will not trigger a failure.
|
||||
*
|
||||
* @param type the type of the fields
|
||||
* @param descriptors the field descriptors
|
||||
* @param attributes the additional attributes
|
||||
* @param ignoreUndocumentedFields whether undocumented fields should be ignored
|
||||
* @param subsectionExtractor the subsection extractor
|
||||
* @since 1.2.0
|
||||
*/
|
||||
protected AbstractFieldsSnippet(String type, List<FieldDescriptor> descriptors,
|
||||
Map<String, Object> attributes, boolean ignoreUndocumentedFields,
|
||||
PayloadSubsectionExtractor<?> subsectionExtractor) {
|
||||
this(type, type, descriptors, attributes, ignoreUndocumentedFields,
|
||||
subsectionExtractor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@code AbstractFieldsSnippet} that will produce a snippet named
|
||||
* {@code <name>-fields} using a template named {@code <type>-fields}. The fields will
|
||||
@@ -98,7 +123,35 @@ public abstract class AbstractFieldsSnippet extends TemplatedSnippet {
|
||||
protected AbstractFieldsSnippet(String name, String type,
|
||||
List<FieldDescriptor> descriptors, Map<String, Object> attributes,
|
||||
boolean ignoreUndocumentedFields) {
|
||||
super(name + "-fields", type + "-fields", attributes);
|
||||
this(name, type, descriptors, attributes, ignoreUndocumentedFields, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@code AbstractFieldsSnippet} that will produce a snippet named
|
||||
* {@code <name>-fields} using a template named {@code <type>-fields}. The fields in
|
||||
* the subsection of the payload identified by {@code subsectionPath} will be
|
||||
* documented using the given {@code descriptors} and the given {@code attributes}
|
||||
* will be included in the model during template rendering. If
|
||||
* {@code ignoreUndocumentedFields} is {@code true}, undocumented fields will be
|
||||
* ignored and will not trigger a failure.
|
||||
*
|
||||
* @param name the name of the snippet
|
||||
* @param type the type of the fields
|
||||
* @param descriptors the field descriptors
|
||||
* @param attributes the additional attributes
|
||||
* @param ignoreUndocumentedFields whether undocumented fields should be ignored
|
||||
* @param subsectionExtractor the subsection extractor documented. {@code null} or an
|
||||
* empty string can be used to indicate that the entire payload should be documented.
|
||||
* @since 1.2.0
|
||||
*/
|
||||
protected AbstractFieldsSnippet(String name, String type,
|
||||
List<FieldDescriptor> descriptors, Map<String, Object> attributes,
|
||||
boolean ignoreUndocumentedFields,
|
||||
PayloadSubsectionExtractor<?> subsectionExtractor) {
|
||||
super(name + "-fields"
|
||||
+ (subsectionExtractor != null
|
||||
? "-" + subsectionExtractor.getSubsectionId() : ""),
|
||||
type + "-fields", attributes);
|
||||
for (FieldDescriptor descriptor : descriptors) {
|
||||
Assert.notNull(descriptor.getPath(), "Field descriptors must have a path");
|
||||
if (!descriptor.isIgnored()) {
|
||||
@@ -112,11 +165,24 @@ public abstract class AbstractFieldsSnippet extends TemplatedSnippet {
|
||||
this.fieldDescriptors = descriptors;
|
||||
this.ignoreUndocumentedFields = ignoreUndocumentedFields;
|
||||
this.type = type;
|
||||
this.subsectionExtractor = subsectionExtractor;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<String, Object> createModel(Operation operation) {
|
||||
ContentHandler contentHandler = getContentHandler(operation);
|
||||
byte[] content;
|
||||
try {
|
||||
content = verifyContent(getContent(operation));
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new ModelCreationException(ex);
|
||||
}
|
||||
MediaType contentType = getContentType(operation);
|
||||
if (this.subsectionExtractor != null) {
|
||||
content = verifyContent(
|
||||
this.subsectionExtractor.extractSubsection(content, contentType));
|
||||
}
|
||||
ContentHandler contentHandler = getContentHandler(content, contentType);
|
||||
|
||||
validateFieldDocumentation(contentHandler);
|
||||
|
||||
@@ -146,28 +212,27 @@ public abstract class AbstractFieldsSnippet extends TemplatedSnippet {
|
||||
return model;
|
||||
}
|
||||
|
||||
private ContentHandler getContentHandler(Operation operation) {
|
||||
MediaType contentType = getContentType(operation);
|
||||
ContentHandler contentHandler;
|
||||
private byte[] verifyContent(byte[] content) {
|
||||
if (content.length == 0) {
|
||||
throw new SnippetException("Cannot document " + this.type + " fields as the "
|
||||
+ this.type + " body is empty");
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
private ContentHandler getContentHandler(byte[] content, MediaType contentType) {
|
||||
try {
|
||||
byte[] content = getContent(operation);
|
||||
if (content.length == 0) {
|
||||
throw new SnippetException("Cannot document " + this.type
|
||||
+ " fields as the " + this.type + " body is empty");
|
||||
}
|
||||
if (contentType != null
|
||||
&& MediaType.APPLICATION_XML.isCompatibleWith(contentType)) {
|
||||
contentHandler = new XmlContentHandler(content);
|
||||
return new XmlContentHandler(content);
|
||||
}
|
||||
else {
|
||||
contentHandler = new JsonContentHandler(content);
|
||||
return new JsonContentHandler(content);
|
||||
}
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new ModelCreationException(ex);
|
||||
}
|
||||
return contentHandler;
|
||||
}
|
||||
|
||||
private void validateFieldDocumentation(ContentHandler payloadHandler) {
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright 2014-2016 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
|
||||
*
|
||||
* http://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.restdocs.payload;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import org.springframework.http.MediaType;
|
||||
|
||||
/**
|
||||
* A {@link PayloadSubsectionExtractor} that extracts the subsection of the JSON payload
|
||||
* identified by a field path.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @since 1.2.0
|
||||
* @see PayloadDocumentation#beneathPath(String)
|
||||
*/
|
||||
public class FieldPathPayloadSubsectionExtractor
|
||||
implements PayloadSubsectionExtractor<FieldPathPayloadSubsectionExtractor> {
|
||||
|
||||
private final String fieldPath;
|
||||
|
||||
private final String subsectionId;
|
||||
|
||||
/**
|
||||
* Creates a new {@code FieldPathPayloadSubsectionExtractor} that will extract the
|
||||
* subsection of the JSON payload found at the given {@code fieldPath}. The
|
||||
* {@code fieldPath} prefixed with {@code beneath-} with be used as the subsection ID.
|
||||
*
|
||||
* @param fieldPath the path of the field
|
||||
*/
|
||||
protected FieldPathPayloadSubsectionExtractor(String fieldPath) {
|
||||
this(fieldPath, "beneath-" + fieldPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@code FieldPathPayloadSubsectionExtractor} that will extract the
|
||||
* subsection of the JSON payload found at the given {@code fieldPath} and that will
|
||||
* us the given {@code subsectionId} to identify the subsection.
|
||||
*
|
||||
* @param fieldPath the path of the field
|
||||
* @param subsectionId the ID of the subsection
|
||||
*/
|
||||
protected FieldPathPayloadSubsectionExtractor(String fieldPath, String subsectionId) {
|
||||
this.fieldPath = fieldPath;
|
||||
this.subsectionId = subsectionId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] extractSubsection(byte[] payload, MediaType contentType) {
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
try {
|
||||
JsonFieldPath compiledPath = JsonFieldPath.compile(this.fieldPath);
|
||||
Object extracted = new JsonFieldProcessor().extract(compiledPath,
|
||||
objectMapper.readValue(payload, Object.class));
|
||||
if (extracted instanceof List && !compiledPath.isPrecise()) {
|
||||
List<?> extractedList = (List<?>) extracted;
|
||||
if (extractedList.size() == 1) {
|
||||
extracted = extractedList.get(0);
|
||||
}
|
||||
else {
|
||||
throw new PayloadHandlingException(this.fieldPath
|
||||
+ " does not uniquely identify a subsection of the payload");
|
||||
}
|
||||
}
|
||||
return objectMapper.writeValueAsBytes(extracted);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new PayloadHandlingException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSubsectionId() {
|
||||
return this.subsectionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the path of the field that will be extracted.
|
||||
*
|
||||
* @return the path of the field
|
||||
*/
|
||||
protected String getFieldPath() {
|
||||
return this.fieldPath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldPathPayloadSubsectionExtractor withSubsectionId(String subsectionId) {
|
||||
return new FieldPathPayloadSubsectionExtractor(this.fieldPath, subsectionId);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -268,6 +268,216 @@ public abstract class PayloadDocumentation {
|
||||
return new RequestFieldsSnippet(descriptors, attributes, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code Snippet} that will document the fields of the subsection of API
|
||||
* operations's request payload extracted by the given {@code subsectionExtractor}.
|
||||
* The fields will be documented using the given {@code descriptors}.
|
||||
* <p>
|
||||
* If a field is present in the request payload, but is not documented by one of the
|
||||
* descriptors, a failure will occur when the snippet is invoked. Similarly, if a
|
||||
* field is documented, is not marked as optional, and is not present in the request,
|
||||
* a failure will also occur. For payloads with a hierarchical structure, documenting
|
||||
* a field is sufficient for all of its descendants to also be treated as having been
|
||||
* documented.
|
||||
* <p>
|
||||
* If you do not want to document a field, a field descriptor can be marked as
|
||||
* {@link FieldDescriptor#ignored}. This will prevent it from appearing in the
|
||||
* generated snippet while avoiding the failure described above.
|
||||
*
|
||||
* @param subsectionExtractor the subsection extractor
|
||||
* @param descriptors the descriptions of the request payload's fields
|
||||
* @return the snippet that will document the fields
|
||||
* @since 1.2.0
|
||||
* @see #fieldWithPath(String)
|
||||
* @see #beneathPath(String)
|
||||
*/
|
||||
public static RequestFieldsSnippet requestFields(
|
||||
PayloadSubsectionExtractor<?> subsectionExtractor,
|
||||
FieldDescriptor... descriptors) {
|
||||
return requestFields(subsectionExtractor, Arrays.asList(descriptors));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code Snippet} that will document the fields in the subsection of the
|
||||
* API operations's request payload extracted by the given {@code subsectionExtractor}
|
||||
* . The fields will be documented using the given {@code descriptors}.
|
||||
* <p>
|
||||
* If a field is present in the request payload, but is not documented by one of the
|
||||
* descriptors, a failure will occur when the snippet is invoked. Similarly, if a
|
||||
* field is documented, is not marked as optional, and is not present in the request,
|
||||
* a failure will also occur. For payloads with a hierarchical structure, documenting
|
||||
* a field is sufficient for all of its descendants to also be treated as having been
|
||||
* documented.
|
||||
* <p>
|
||||
* If you do not want to document a field, a field descriptor can be marked as
|
||||
* {@link FieldDescriptor#ignored}. This will prevent it from appearing in the
|
||||
* generated snippet while avoiding the failure described above.
|
||||
*
|
||||
* @param subsectionExtractor the subsection extractor
|
||||
* @param descriptors the descriptions of the request payload's fields
|
||||
* @return the snippet that will document the fields
|
||||
* @since 1.2.0
|
||||
* @see #fieldWithPath(String)
|
||||
* @see #beneathPath(String)
|
||||
*/
|
||||
public static RequestFieldsSnippet requestFields(
|
||||
PayloadSubsectionExtractor<?> subsectionExtractor,
|
||||
List<FieldDescriptor> descriptors) {
|
||||
return new RequestFieldsSnippet(subsectionExtractor, descriptors);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code Snippet} that will document the fields of the subsection of the
|
||||
* API operations's request payload extracted by the given {@code subsectionExtractor}
|
||||
* . The fields will be documented using the given {@code descriptors}.
|
||||
* <p>
|
||||
* If a field is documented, is not marked as optional, and is not present in the
|
||||
* request, a failure will occur. Any undocumented fields will be ignored.
|
||||
*
|
||||
* @param subsectionExtractor the subsection extractor
|
||||
* @param descriptors the descriptions of the request payload's fields
|
||||
* @return the snippet that will document the fields
|
||||
* @since 1.2.0
|
||||
* @see #fieldWithPath(String)
|
||||
* @see #beneathPath(String)
|
||||
*/
|
||||
public static RequestFieldsSnippet relaxedRequestFields(
|
||||
PayloadSubsectionExtractor<?> subsectionExtractor,
|
||||
FieldDescriptor... descriptors) {
|
||||
return relaxedRequestFields(subsectionExtractor, Arrays.asList(descriptors));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code Snippet} that will document the fields of the subsection of the
|
||||
* API operations's request payload extracted by the given {@code subsectionExtractor}
|
||||
* . The fields will be documented using the given {@code descriptors}.
|
||||
* <p>
|
||||
* If a field is documented, is not marked as optional, and is not present in the
|
||||
* request, a failure will occur. Any undocumented fields will be ignored.
|
||||
*
|
||||
* @param subsectionExtractor the subsection extractor
|
||||
* @param descriptors the descriptions of the request payload's fields
|
||||
* @return the snippet that will document the fields
|
||||
* @since 1.2.0
|
||||
* @see #fieldWithPath(String)
|
||||
* @see #beneathPath(String)
|
||||
*/
|
||||
public static RequestFieldsSnippet relaxedRequestFields(
|
||||
PayloadSubsectionExtractor<?> subsectionExtractor,
|
||||
List<FieldDescriptor> descriptors) {
|
||||
return new RequestFieldsSnippet(subsectionExtractor, descriptors, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code Snippet} that will document the fields of the subsection of the
|
||||
* API operation's request payload extracted by the given {@code subsectionExtractor}.
|
||||
* The fields will be documented using the given {@code descriptors} and the given
|
||||
* {@code attributes} will be available during snippet generation.
|
||||
* <p>
|
||||
* If a field is present in the request payload, but is not documented by one of the
|
||||
* descriptors, a failure will occur when the snippet is invoked. Similarly, if a
|
||||
* field is documented, is not marked as optional, and is not present in the request
|
||||
* payload, a failure will also occur. For payloads with a hierarchical structure,
|
||||
* documenting a field is sufficient for all of its descendants to also be treated as
|
||||
* having been documented.
|
||||
* <p>
|
||||
* If you do not want to document a field, a field descriptor can be marked as
|
||||
* {@link FieldDescriptor#ignored}. This will prevent it from appearing in the
|
||||
* generated snippet while avoiding the failure described above.
|
||||
*
|
||||
* @param subsectionExtractor the subsection extractor
|
||||
* @param attributes the attributes
|
||||
* @param descriptors the descriptions of the request payload's fields
|
||||
* @return the snippet that will document the fields
|
||||
* @since 1.2.0
|
||||
* @see #fieldWithPath(String)
|
||||
* @see #beneathPath(String)
|
||||
*/
|
||||
public static RequestFieldsSnippet requestFields(
|
||||
PayloadSubsectionExtractor<?> subsectionExtractor,
|
||||
Map<String, Object> attributes, FieldDescriptor... descriptors) {
|
||||
return requestFields(subsectionExtractor, attributes, Arrays.asList(descriptors));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code Snippet} that will document the fields of the subsection of the
|
||||
* API operation's request payload extracted by the given {@code subsectionExtractor}.
|
||||
* The fields will be documented using the given {@code descriptors} and the given
|
||||
* {@code attributes} will be available during snippet generation.
|
||||
* <p>
|
||||
* If a field is present in the request payload, but is not documented by one of the
|
||||
* descriptors, a failure will occur when the snippet is invoked. Similarly, if a
|
||||
* field is documented, is not marked as optional, and is not present in the request
|
||||
* payload, a failure will also occur. For payloads with a hierarchical structure,
|
||||
* documenting a field is sufficient for all of its descendants to also be treated as
|
||||
* having been documented.
|
||||
* <p>
|
||||
* If you do not want to document a field, a field descriptor can be marked as
|
||||
* {@link FieldDescriptor#ignored}. This will prevent it from appearing in the
|
||||
* generated snippet while avoiding the failure described above.
|
||||
*
|
||||
* @param subsectionExtractor the subsection extractor
|
||||
* @param attributes the attributes
|
||||
* @param descriptors the descriptions of the request payload's fields
|
||||
* @return the snippet that will document the fields
|
||||
* @since 1.2.0
|
||||
* @see #fieldWithPath(String)
|
||||
* @see #beneathPath(String)
|
||||
*/
|
||||
public static RequestFieldsSnippet requestFields(
|
||||
PayloadSubsectionExtractor<?> subsectionExtractor,
|
||||
Map<String, Object> attributes, List<FieldDescriptor> descriptors) {
|
||||
return new RequestFieldsSnippet(subsectionExtractor, descriptors, attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code Snippet} that will document the fields of the subsection of the
|
||||
* API operation's request payload extracted by the given {@code subsectionExtractor}.
|
||||
* The fields will be documented using the given {@code descriptors} and the given
|
||||
* {@code attributes} will be available during snippet generation.
|
||||
* <p>
|
||||
* If a field is documented, is not marked as optional, and is not present in the
|
||||
* request, a failure will occur. Any undocumented fields will be ignored.
|
||||
*
|
||||
* @param subsectionExtractor the subsection extractor
|
||||
* @param attributes the attributes
|
||||
* @param descriptors the descriptions of the request payload's fields
|
||||
* @return the snippet that will document the fields
|
||||
* @since 1.2.0
|
||||
* @see #fieldWithPath(String)
|
||||
* @see #beneathPath(String)
|
||||
*/
|
||||
public static RequestFieldsSnippet relaxedRequestFields(
|
||||
PayloadSubsectionExtractor<?> subsectionExtractor,
|
||||
Map<String, Object> attributes, FieldDescriptor... descriptors) {
|
||||
return relaxedRequestFields(subsectionExtractor, attributes,
|
||||
Arrays.asList(descriptors));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code Snippet} that will document the fields of the subsection of the
|
||||
* API operation's request payload extracted by the given {@code subsectionExtractor}.
|
||||
* The fields will be documented using the given {@code descriptors} and the given
|
||||
* {@code attributes} will be available during snippet generation.
|
||||
* <p>
|
||||
* If a field is documented, is not marked as optional, and is not present in the
|
||||
* request, a failure will occur. Any undocumented fields will be ignored.
|
||||
*
|
||||
* @param subsectionExtractor the subsection extractor
|
||||
* @param attributes the attributes
|
||||
* @param descriptors the descriptions of the request payload's fields
|
||||
* @return the snippet that will document the fields
|
||||
* @since 1.2.0
|
||||
* @see #fieldWithPath(String)
|
||||
* @see #beneathPath(String)
|
||||
*/
|
||||
public static RequestFieldsSnippet relaxedRequestFields(
|
||||
PayloadSubsectionExtractor<?> subsectionExtractor,
|
||||
Map<String, Object> attributes, List<FieldDescriptor> descriptors) {
|
||||
return new RequestFieldsSnippet(subsectionExtractor, descriptors, attributes,
|
||||
true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code Snippet} that will document the fields of the specified
|
||||
* {@code part} of the API operations's request payload. The fields will be documented
|
||||
@@ -287,6 +497,7 @@ public abstract class PayloadDocumentation {
|
||||
* @param part the part name
|
||||
* @param descriptors the descriptions of the request part's fields
|
||||
* @return the snippet that will document the fields
|
||||
* @since 1.2.0
|
||||
* @see #fieldWithPath(String)
|
||||
*/
|
||||
public static RequestPartFieldsSnippet requestPartFields(String part,
|
||||
@@ -452,6 +663,235 @@ public abstract class PayloadDocumentation {
|
||||
return new RequestPartFieldsSnippet(part, descriptors, attributes, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code Snippet} that will document the fields of a subsection of the
|
||||
* specified {@code part} of the API operations's request payload. The subsection will
|
||||
* be extracted by the given {@code subsectionExtractor}. The fields will be
|
||||
* documented using the given {@code descriptors}.
|
||||
* <p>
|
||||
* If a field is present in the request part, but is not documented by one of the
|
||||
* descriptors, a failure will occur when the snippet is invoked. Similarly, if a
|
||||
* field is documented, is not marked as optional, and is not present in the request
|
||||
* part, a failure will also occur. For payloads with a hierarchical structure,
|
||||
* documenting a field is sufficient for all of its descendants to also be treated as
|
||||
* having been documented.
|
||||
* <p>
|
||||
* If you do not want to document a field, a field descriptor can be marked as
|
||||
* {@link FieldDescriptor#ignored}. This will prevent it from appearing in the
|
||||
* generated snippet while avoiding the failure described above.
|
||||
*
|
||||
* @param part the part name
|
||||
* @param subsectionExtractor the subsection extractor
|
||||
* @param descriptors the descriptions of the subsection's fields
|
||||
* @return the snippet that will document the fields
|
||||
* @since 1.2.0
|
||||
* @see #fieldWithPath(String)
|
||||
* @see #beneathPath(String)
|
||||
*/
|
||||
public static RequestPartFieldsSnippet requestPartFields(String part,
|
||||
PayloadSubsectionExtractor<?> subsectionExtractor,
|
||||
FieldDescriptor... descriptors) {
|
||||
return requestPartFields(part, subsectionExtractor, Arrays.asList(descriptors));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code Snippet} that will document the fields of a subsection of the
|
||||
* specified {@code part} of the API operations's request payload. The subsection will
|
||||
* be extracted by the given {@code subsectionExtractor}. The fields will be
|
||||
* documented using the given {@code descriptors}.
|
||||
* <p>
|
||||
* If a field is present in the request part, but is not documented by one of the
|
||||
* descriptors, a failure will occur when the snippet is invoked. Similarly, if a
|
||||
* field is documented, is not marked as optional, and is not present in the request
|
||||
* part, a failure will also occur. For payloads with a hierarchical structure,
|
||||
* documenting a field is sufficient for all of its descendants to also be treated as
|
||||
* having been documented.
|
||||
* <p>
|
||||
* If you do not want to document a field, a field descriptor can be marked as
|
||||
* {@link FieldDescriptor#ignored}. This will prevent it from appearing in the
|
||||
* generated snippet while avoiding the failure described above.
|
||||
*
|
||||
* @param part the part name
|
||||
* @param subsectionExtractor the subsection extractor
|
||||
* @param descriptors the descriptions of the subsection's fields
|
||||
* @return the snippet that will document the fields
|
||||
* @since 1.2.0
|
||||
* @see #fieldWithPath(String)
|
||||
* @see #beneathPath(String)
|
||||
*/
|
||||
public static RequestPartFieldsSnippet requestPartFields(String part,
|
||||
PayloadSubsectionExtractor<?> subsectionExtractor,
|
||||
List<FieldDescriptor> descriptors) {
|
||||
return new RequestPartFieldsSnippet(part, subsectionExtractor, descriptors);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code Snippet} that will document the fields of a subsection of the
|
||||
* specified {@code part} of the API operations's request payload. The subsection will
|
||||
* be extracted by the given {@code subsectionExtractor}. The fields will be
|
||||
* documented using the given {@code descriptors}.
|
||||
* <p>
|
||||
* If a field is documented, is not marked as optional, and is not present in the
|
||||
* request, a failure will occur. Any undocumented fields will be ignored.
|
||||
*
|
||||
* @param part the part name
|
||||
* @param subsectionExtractor the subsection extractor
|
||||
* @param descriptors the descriptions of the request part's fields
|
||||
* @return the snippet that will document the fields
|
||||
* @since 1.2.0
|
||||
* @see #fieldWithPath(String)
|
||||
* @see #beneathPath(String)
|
||||
*/
|
||||
public static RequestPartFieldsSnippet relaxedRequestPartFields(String part,
|
||||
PayloadSubsectionExtractor<?> subsectionExtractor,
|
||||
FieldDescriptor... descriptors) {
|
||||
return relaxedRequestPartFields(part, subsectionExtractor,
|
||||
Arrays.asList(descriptors));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code Snippet} that will document the fields of a subsection of the
|
||||
* specified {@code part} of the API operations's request payload. The subsection will
|
||||
* be extracted by the given {@code subsectionExtractor}. The fields will be
|
||||
* documented using the given {@code descriptors}.
|
||||
* <p>
|
||||
* If a field is documented, is not marked as optional, and is not present in the
|
||||
* request, a failure will occur. Any undocumented fields will be ignored.
|
||||
*
|
||||
* @param part the part name
|
||||
* @param subsectionExtractor the subsection extractor
|
||||
* @param descriptors the descriptions of the request part's fields
|
||||
* @return the snippet that will document the fields
|
||||
* @since 1.2.0
|
||||
* @see #fieldWithPath(String)
|
||||
* @see #beneathPath(String)
|
||||
*/
|
||||
public static RequestPartFieldsSnippet relaxedRequestPartFields(String part,
|
||||
PayloadSubsectionExtractor<?> subsectionExtractor,
|
||||
List<FieldDescriptor> descriptors) {
|
||||
return new RequestPartFieldsSnippet(part, subsectionExtractor, descriptors, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code Snippet} that will document the fields of a subsection of the
|
||||
* specified {@code part} of the API operations's request payload. The subsection will
|
||||
* be extracted by the givne {@code subsectionExtractor}. The fields will be
|
||||
* documented using the given {@code descriptors} and the given {@code attributes}
|
||||
* will be available during snippet generation.
|
||||
* <p>
|
||||
* If a field is present in the request part, but is not documented by one of the
|
||||
* descriptors, a failure will occur when the snippet is invoked. Similarly, if a
|
||||
* field is documented, is not marked as optional, and is not present in the request
|
||||
* part, a failure will also occur. For payloads with a hierarchical structure,
|
||||
* documenting a field is sufficient for all of its descendants to also be treated as
|
||||
* having been documented.
|
||||
* <p>
|
||||
* If you do not want to document a field, a field descriptor can be marked as
|
||||
* {@link FieldDescriptor#ignored}. This will prevent it from appearing in the
|
||||
* generated snippet while avoiding the failure described above.
|
||||
*
|
||||
* @param part the part name
|
||||
* @param subsectionExtractor the subsection extractor
|
||||
* @param attributes the attributes
|
||||
* @param descriptors the descriptions of the request part's fields
|
||||
* @return the snippet that will document the fields
|
||||
* @since 1.2.0
|
||||
* @see #fieldWithPath(String)
|
||||
* @see #beneathPath(String)
|
||||
*/
|
||||
public static RequestPartFieldsSnippet requestPartFields(String part,
|
||||
PayloadSubsectionExtractor<?> subsectionExtractor,
|
||||
Map<String, Object> attributes, FieldDescriptor... descriptors) {
|
||||
return requestPartFields(part, subsectionExtractor, attributes,
|
||||
Arrays.asList(descriptors));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code Snippet} that will document the fields of a subsection of the
|
||||
* specified {@code part} of the API operations's request payload. The subsection will
|
||||
* be extracted by the given {@code subsectionExtractor}. The fields will be
|
||||
* documented using the given {@code descriptors} and the given {@code attributes}
|
||||
* will be available during snippet generation.
|
||||
* <p>
|
||||
* If a field is present in the request part, but is not documented by one of the
|
||||
* descriptors, a failure will occur when the snippet is invoked. Similarly, if a
|
||||
* field is documented, is not marked as optional, and is not present in the request
|
||||
* part, a failure will also occur. For payloads with a hierarchical structure,
|
||||
* documenting a field is sufficient for all of its descendants to also be treated as
|
||||
* having been documented.
|
||||
* <p>
|
||||
* If you do not want to document a field, a field descriptor can be marked as
|
||||
* {@link FieldDescriptor#ignored}. This will prevent it from appearing in the
|
||||
* generated snippet while avoiding the failure described above.
|
||||
*
|
||||
* @param part the part name
|
||||
* @param subsectionExtractor the subsection extractor
|
||||
* @param attributes the attributes
|
||||
* @param descriptors the descriptions of the request part's fields
|
||||
* @return the snippet that will document the fields
|
||||
* @since 1.2.0
|
||||
* @see #fieldWithPath(String)
|
||||
* @see #beneathPath(String)
|
||||
*/
|
||||
public static RequestPartFieldsSnippet requestPartFields(String part,
|
||||
PayloadSubsectionExtractor<?> subsectionExtractor,
|
||||
Map<String, Object> attributes, List<FieldDescriptor> descriptors) {
|
||||
return new RequestPartFieldsSnippet(part, subsectionExtractor, descriptors,
|
||||
attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code Snippet} that will document the fields of a subsection of the
|
||||
* specified {@code part} of the API operations's request payload. The subsection will
|
||||
* be extracted by the given {@code subsectionExtractor}. The fields will be
|
||||
* documented using the given {@code descriptors} and the given {@code attributes}
|
||||
* will be available during snippet generation.
|
||||
* <p>
|
||||
* If a field is documented, is not marked as optional, and is not present in the
|
||||
* request, a failure will occur. Any undocumented fields will be ignored.
|
||||
*
|
||||
* @param part the part name
|
||||
* @param subsectionExtractor the subsection extractor
|
||||
* @param attributes the attributes
|
||||
* @param descriptors the descriptions of the request part's fields
|
||||
* @return the snippet that will document the fields
|
||||
* @since 1.2.0
|
||||
* @see #fieldWithPath(String)
|
||||
* @see #beneathPath(String)
|
||||
*/
|
||||
public static RequestPartFieldsSnippet relaxedRequestPartFields(String part,
|
||||
PayloadSubsectionExtractor<?> subsectionExtractor,
|
||||
Map<String, Object> attributes, FieldDescriptor... descriptors) {
|
||||
return relaxedRequestPartFields(part, subsectionExtractor, attributes,
|
||||
Arrays.asList(descriptors));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code Snippet} that will document the fields of a subsection of the
|
||||
* specified {@code part} of the API operations's request payload. The subsection will
|
||||
* be extracted by the given {@code subsectionExtractor}. The fields will be
|
||||
* documented using the given {@code descriptors} and the given {@code attributes}
|
||||
* will be available during snippet generation.
|
||||
* <p>
|
||||
* If a field is documented, is not marked as optional, and is not present in the
|
||||
* request, a failure will occur. Any undocumented fields will be ignored.
|
||||
*
|
||||
* @param part the part name
|
||||
* @param subsectionExtractor the subsection extractor
|
||||
* @param attributes the attributes
|
||||
* @param descriptors the descriptions of the request part's fields
|
||||
* @return the snippet that will document the fields
|
||||
* @since 1.2.0
|
||||
* @see #fieldWithPath(String)
|
||||
* @see #beneathPath(String)
|
||||
*/
|
||||
public static RequestPartFieldsSnippet relaxedRequestPartFields(String part,
|
||||
PayloadSubsectionExtractor<?> subsectionExtractor,
|
||||
Map<String, Object> attributes, List<FieldDescriptor> descriptors) {
|
||||
return new RequestPartFieldsSnippet(part, subsectionExtractor, descriptors,
|
||||
attributes, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code Snippet} that will document the fields of the API operation's
|
||||
* response payload. The fields will be documented using the given {@code descriptors}
|
||||
@@ -494,7 +934,9 @@ public abstract class PayloadDocumentation {
|
||||
*
|
||||
* @param descriptors the descriptions of the response payload's fields
|
||||
* @return the snippet that will document the fields
|
||||
* @since 1.2.0
|
||||
* @see #fieldWithPath(String)
|
||||
* @see #beneathPath(String)
|
||||
*/
|
||||
public static ResponseFieldsSnippet responseFields(
|
||||
List<FieldDescriptor> descriptors) {
|
||||
@@ -511,7 +953,9 @@ public abstract class PayloadDocumentation {
|
||||
*
|
||||
* @param descriptors the descriptions of the response payload's fields
|
||||
* @return the snippet that will document the fields
|
||||
* @since 1.2.0
|
||||
* @see #fieldWithPath(String)
|
||||
* @see #beneathPath(String)
|
||||
*/
|
||||
public static ResponseFieldsSnippet relaxedResponseFields(
|
||||
FieldDescriptor... descriptors) {
|
||||
@@ -623,6 +1067,225 @@ public abstract class PayloadDocumentation {
|
||||
return new ResponseFieldsSnippet(descriptors, attributes, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code Snippet} that will document the fields of a subsection of the API
|
||||
* operation's response payload. The subsection will be extracted using the given
|
||||
* {@code subsectionExtractor}. The fields will be documented using the given
|
||||
* {@code descriptors} .
|
||||
* <p>
|
||||
* If a field is present in the response payload, but is not documented by one of the
|
||||
* descriptors, a failure will occur when the snippet is invoked. Similarly, if a
|
||||
* field is documented, is not marked as optional, and is not present in the response
|
||||
* payload, a failure will also occur. For payloads with a hierarchical structure,
|
||||
* documenting a field is sufficient for all of its descendants to also be treated as
|
||||
* having been documented.
|
||||
* <p>
|
||||
* If you do not want to document a field, a field descriptor can be marked as
|
||||
* {@link FieldDescriptor#ignored}. This will prevent it from appearing in the
|
||||
* generated snippet while avoiding the failure described above.
|
||||
*
|
||||
* @param subsectionExtractor the subsection extractor
|
||||
* @param descriptors the descriptions of the response payload's fields
|
||||
* @return the snippet that will document the fields
|
||||
* @since 1.2.0
|
||||
* @see #fieldWithPath(String)
|
||||
* @see #beneathPath(String)
|
||||
*/
|
||||
public static ResponseFieldsSnippet responseFields(
|
||||
PayloadSubsectionExtractor<?> subsectionExtractor,
|
||||
FieldDescriptor... descriptors) {
|
||||
return responseFields(subsectionExtractor, Arrays.asList(descriptors));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code Snippet} that will document the fields of a subsection of the API
|
||||
* operation's response payload. The subsection will be extracted using the given
|
||||
* {@code subsectionExtractor}. The fields will be documented using the given
|
||||
* {@code descriptors} .
|
||||
* <p>
|
||||
* If a field is present in the response payload, but is not documented by one of the
|
||||
* descriptors, a failure will occur when the snippet is invoked. Similarly, if a
|
||||
* field is documented, is not marked as optional, and is not present in the response
|
||||
* payload, a failure will also occur. For payloads with a hierarchical structure,
|
||||
* documenting a field is sufficient for all of its descendants to also be treated as
|
||||
* having been documented.
|
||||
* <p>
|
||||
* If you do not want to document a field, a field descriptor can be marked as
|
||||
* {@link FieldDescriptor#ignored}. This will prevent it from appearing in the
|
||||
* generated snippet while avoiding the failure described above.
|
||||
*
|
||||
* @param subsectionExtractor the subsection extractor
|
||||
* @param descriptors the descriptions of the response payload's fields
|
||||
* @return the snippet that will document the fields
|
||||
* @since 1.2.0
|
||||
* @see #fieldWithPath(String)
|
||||
* @see #beneathPath(String)
|
||||
*/
|
||||
public static ResponseFieldsSnippet responseFields(
|
||||
PayloadSubsectionExtractor<?> subsectionExtractor,
|
||||
List<FieldDescriptor> descriptors) {
|
||||
return new ResponseFieldsSnippet(subsectionExtractor, descriptors);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code Snippet} that will document the fields of a subsection of the API
|
||||
* operation's response payload. The subsection will be extracted using the given
|
||||
* {@code subsectionExtractor}. The fields will be documented using the given
|
||||
* {@code descriptors} .
|
||||
* <p>
|
||||
* If a field is documented, is not marked as optional, and is not present in the
|
||||
* request, a failure will occur. Any undocumented fields will be ignored.
|
||||
*
|
||||
* @param subsectionExtractor the subsection extractor
|
||||
* @param descriptors the descriptions of the response payload's fields
|
||||
* @return the snippet that will document the fields
|
||||
* @since 1.2.0
|
||||
* @see #fieldWithPath(String)
|
||||
* @see #beneathPath(String)
|
||||
*/
|
||||
public static ResponseFieldsSnippet relaxedResponseFields(
|
||||
PayloadSubsectionExtractor<?> subsectionExtractor,
|
||||
FieldDescriptor... descriptors) {
|
||||
return relaxedResponseFields(subsectionExtractor, Arrays.asList(descriptors));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code Snippet} that will document the fields of a subsection of the API
|
||||
* operation's response payload. The subsection will be extracted using the given
|
||||
* {@code subsectionExtractor}. The fields will be documented using the given
|
||||
* {@code descriptors} .
|
||||
* <p>
|
||||
* If a field is documented, is not marked as optional, and is not present in the
|
||||
* request, a failure will occur. Any undocumented fields will be ignored.
|
||||
*
|
||||
* @param subsectionExtractor the subsection extractor
|
||||
* @param descriptors the descriptions of the response payload's fields
|
||||
* @return the snippet that will document the fields
|
||||
* @since 1.2.0
|
||||
* @see #fieldWithPath(String)
|
||||
* @see #beneathPath(String)
|
||||
*/
|
||||
public static ResponseFieldsSnippet relaxedResponseFields(
|
||||
PayloadSubsectionExtractor<?> subsectionExtractor,
|
||||
List<FieldDescriptor> descriptors) {
|
||||
return new ResponseFieldsSnippet(subsectionExtractor, descriptors, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code Snippet} that will document the fields of a subsection of the API
|
||||
* operation's response payload. The subsection will be extracted using the given
|
||||
* {@code subsectionExtractor}. The fields will be documented using the given
|
||||
* {@code descriptors} and the given {@code attributes} will be available during
|
||||
* snippet generation.
|
||||
* <p>
|
||||
* If a field is present in the response payload, but is not documented by one of the
|
||||
* descriptors, a failure will occur when the snippet is invoked. Similarly, if a
|
||||
* field is documented, is not marked as optional, and is not present in the response
|
||||
* payload, a failure will also occur. For payloads with a hierarchical structure,
|
||||
* documenting a field is sufficient for all of its descendants to also be treated as
|
||||
* having been documented.
|
||||
* <p>
|
||||
* If you do not want to document a field, a field descriptor can be marked as
|
||||
* {@link FieldDescriptor#ignored}. This will prevent it from appearing in the
|
||||
* generated snippet while avoiding the failure described above.
|
||||
*
|
||||
* @param subsectionExtractor the subsection extractor
|
||||
* @param attributes the attributes
|
||||
* @param descriptors the descriptions of the response payload's fields
|
||||
* @return the snippet that will document the fields
|
||||
* @since 1.2.0
|
||||
* @see #fieldWithPath(String)
|
||||
* @see #beneathPath(String)
|
||||
*/
|
||||
public static ResponseFieldsSnippet responseFields(
|
||||
PayloadSubsectionExtractor<?> subsectionExtractor,
|
||||
Map<String, Object> attributes, FieldDescriptor... descriptors) {
|
||||
return responseFields(subsectionExtractor, attributes,
|
||||
Arrays.asList(descriptors));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code Snippet} that will document the fields of a subsection of the API
|
||||
* operation's response payload. The subsection will be extracted using the given
|
||||
* {@code subsectionExtractor}. The fields will be documented using the given
|
||||
* {@code descriptors} and the given {@code attributes} will be available during
|
||||
* snippet generation.
|
||||
* <p>
|
||||
* If a field is present in the response payload, but is not documented by one of the
|
||||
* descriptors, a failure will occur when the snippet is invoked. Similarly, if a
|
||||
* field is documented, is not marked as optional, and is not present in the response
|
||||
* payload, a failure will also occur. For payloads with a hierarchical structure,
|
||||
* documenting a field is sufficient for all of its descendants to also be treated as
|
||||
* having been documented.
|
||||
* <p>
|
||||
* If you do not want to document a field, a field descriptor can be marked as
|
||||
* {@link FieldDescriptor#ignored}. This will prevent it from appearing in the
|
||||
* generated snippet while avoiding the failure described above.
|
||||
*
|
||||
* @param subsectionExtractor the subsection extractor
|
||||
* @param attributes the attributes
|
||||
* @param descriptors the descriptions of the response payload's fields
|
||||
* @return the snippet that will document the fields
|
||||
* @since 1.2.0
|
||||
* @see #fieldWithPath(String)
|
||||
* @see #beneathPath(String)
|
||||
*/
|
||||
public static ResponseFieldsSnippet responseFields(
|
||||
PayloadSubsectionExtractor<?> subsectionExtractor,
|
||||
Map<String, Object> attributes, List<FieldDescriptor> descriptors) {
|
||||
return new ResponseFieldsSnippet(subsectionExtractor, descriptors, attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code Snippet} that will document the fields of a subsection of the API
|
||||
* operation's response payload. The subsection will be extracted using the given
|
||||
* {@code subsectionExtractor}. The fields will be documented using the given
|
||||
* {@code descriptors} and the given {@code attributes} will be available during
|
||||
* snippet generation.
|
||||
* <p>
|
||||
* If a field is documented, is not marked as optional, and is not present in the
|
||||
* request, a failure will occur. Any undocumented fields will be ignored.
|
||||
*
|
||||
* @param subsectionExtractor the subsection extractor
|
||||
* @param attributes the attributes
|
||||
* @param descriptors the descriptions of the response payload's fields
|
||||
* @return the snippet that will document the fields
|
||||
* @since 1.2.0
|
||||
* @see #fieldWithPath(String)
|
||||
* @see #beneathPath(String)
|
||||
*/
|
||||
public static ResponseFieldsSnippet relaxedResponseFields(
|
||||
PayloadSubsectionExtractor<?> subsectionExtractor,
|
||||
Map<String, Object> attributes, FieldDescriptor... descriptors) {
|
||||
return relaxedResponseFields(subsectionExtractor, attributes,
|
||||
Arrays.asList(descriptors));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code Snippet} that will document the fields of a subsection of the API
|
||||
* operation's response payload. The subsection will be extracted using the given
|
||||
* {@code subsectionExtractor}. The fields will be documented using the given
|
||||
* {@code descriptors} and the given {@code attributes} will be available during
|
||||
* snippet generation.
|
||||
* <p>
|
||||
* If a field is documented, is not marked as optional, and is not present in the
|
||||
* request, a failure will occur. Any undocumented fields will be ignored.
|
||||
*
|
||||
* @param subsectionExtractor the subsection extractor
|
||||
* @param attributes the attributes
|
||||
* @param descriptors the descriptions of the response payload's fields
|
||||
* @return the snippet that will document the fields
|
||||
* @since 1.2.0
|
||||
* @see #fieldWithPath(String)
|
||||
* @see #beneathPath(String)
|
||||
*/
|
||||
public static ResponseFieldsSnippet relaxedResponseFields(
|
||||
PayloadSubsectionExtractor<?> subsectionExtractor,
|
||||
Map<String, Object> attributes, List<FieldDescriptor> descriptors) {
|
||||
return new ResponseFieldsSnippet(subsectionExtractor, descriptors, attributes,
|
||||
true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a copy of the given {@code descriptors} with the given {@code pathPrefix}
|
||||
* applied to their paths.
|
||||
@@ -651,6 +1314,18 @@ public abstract class PayloadDocumentation {
|
||||
return prefixedDescriptors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link PayloadSubsectionExtractor} that will extract the subsection of
|
||||
* the JSON payload found beneath the given {@code path}.
|
||||
*
|
||||
* @param path the path
|
||||
* @return the subsection extractor
|
||||
* @since 1.2.0
|
||||
*/
|
||||
public static PayloadSubsectionExtractor<?> beneathPath(String path) {
|
||||
return new FieldPathPayloadSubsectionExtractor(path);
|
||||
}
|
||||
|
||||
private static Attribute[] asArray(Map<String, Object> attributeMap) {
|
||||
List<Attributes.Attribute> attributes = new ArrayList<>();
|
||||
for (Map.Entry<String, Object> attribute : attributeMap.entrySet()) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2015 the original author or authors.
|
||||
* Copyright 2014-2016 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.
|
||||
@@ -26,7 +26,18 @@ package org.springframework.restdocs.payload;
|
||||
class PayloadHandlingException extends RuntimeException {
|
||||
|
||||
/**
|
||||
* Creates a new {@code PayloadHandlingException} with the given cause.
|
||||
* Creates a new {@code PayloadHandlingException} with the given {@code message}.
|
||||
*
|
||||
* @param message the message
|
||||
* @since 1.2.0
|
||||
*/
|
||||
PayloadHandlingException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@code PayloadHandlingException} with the given {@code cause}.
|
||||
*
|
||||
* @param cause the cause of the failure
|
||||
*/
|
||||
PayloadHandlingException(Throwable cause) {
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2014-2016 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
|
||||
*
|
||||
* http://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.restdocs.payload;
|
||||
|
||||
import org.springframework.http.MediaType;
|
||||
|
||||
/**
|
||||
* Strategy interface for extracting a subsection of a payload.
|
||||
*
|
||||
* @param <T> The subsection extractor subclass
|
||||
* @author Andy Wilkinson
|
||||
* @since 1.2.0
|
||||
*/
|
||||
public interface PayloadSubsectionExtractor<T extends PayloadSubsectionExtractor<T>> {
|
||||
|
||||
/**
|
||||
* Extracts a subsection of the given {@code payload} that has the given
|
||||
* {@code contentType}.
|
||||
*
|
||||
* @param payload the payload
|
||||
* @param contentType the content type of the payload
|
||||
* @return the subsection of the payload
|
||||
*/
|
||||
byte[] extractSubsection(byte[] payload, MediaType contentType);
|
||||
|
||||
/**
|
||||
* Returns an identifier for the subsection that this extractor will extract.
|
||||
*
|
||||
* @return the identifier
|
||||
*/
|
||||
String getSubsectionId();
|
||||
|
||||
/**
|
||||
* Returns an extractor with the given {@code subsectionId}.
|
||||
*
|
||||
* @param subsectionId the subsection ID
|
||||
* @return the customized extractor
|
||||
*/
|
||||
T withSubsectionId(String subsectionId);
|
||||
|
||||
}
|
||||
@@ -86,7 +86,74 @@ public class RequestFieldsSnippet extends AbstractFieldsSnippet {
|
||||
*/
|
||||
protected RequestFieldsSnippet(List<FieldDescriptor> descriptors,
|
||||
Map<String, Object> attributes, boolean ignoreUndocumentedFields) {
|
||||
super("request", descriptors, attributes, ignoreUndocumentedFields);
|
||||
this(null, descriptors, attributes, ignoreUndocumentedFields);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@code RequestFieldsSnippet} that will document the fields in the
|
||||
* subsection of the request extracted by the given {@code subsectionExtractor} using
|
||||
* the given {@code descriptors}. Undocumented fields will trigger a failure.
|
||||
*
|
||||
* @param subsectionExtractor the subsection extractor
|
||||
* @param descriptors the descriptors
|
||||
* @since 1.2.0
|
||||
*/
|
||||
protected RequestFieldsSnippet(PayloadSubsectionExtractor<?> subsectionExtractor,
|
||||
List<FieldDescriptor> descriptors) {
|
||||
this(subsectionExtractor, descriptors, null, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@code RequestFieldsSnippet} that will document the fields in the
|
||||
* subsection of the request extracted by the given {@code subsectionExtractor} using
|
||||
* the given {@code descriptors}. If {@code ignoreUndocumentedFields} is {@code true},
|
||||
* undocumented fields will be ignored and will not trigger a failure.
|
||||
*
|
||||
* @param subsectionExtractor the subsection extractor document
|
||||
* @param descriptors the descriptors
|
||||
* @param ignoreUndocumentedFields whether undocumented fields should be ignored
|
||||
* @since 1.2.0
|
||||
*/
|
||||
protected RequestFieldsSnippet(PayloadSubsectionExtractor<?> subsectionExtractor,
|
||||
List<FieldDescriptor> descriptors, boolean ignoreUndocumentedFields) {
|
||||
this(subsectionExtractor, descriptors, null, ignoreUndocumentedFields);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@code RequestFieldsSnippet} that will document the fields in the
|
||||
* subsection of the request extracted by the given {@code subsectionExtractor} using
|
||||
* the given {@code descriptors}. The given {@code attributes} will be included in the
|
||||
* model during template rendering. Undocumented fields will trigger a failure.
|
||||
*
|
||||
* @param subsectionExtractor the subsection extractor
|
||||
* @param descriptors the descriptors
|
||||
* @param attributes the additional attributes
|
||||
* @since 1.2.0
|
||||
*/
|
||||
protected RequestFieldsSnippet(PayloadSubsectionExtractor<?> subsectionExtractor,
|
||||
List<FieldDescriptor> descriptors, Map<String, Object> attributes) {
|
||||
this(subsectionExtractor, descriptors, attributes, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@code RequestFieldsSnippet} that will document the fields in the
|
||||
* subsection of the request extracted by the given {@code subsectionExtractor} using
|
||||
* the given {@code descriptors}. The given {@code attributes} will be included in the
|
||||
* model during template rendering. If {@code ignoreUndocumentedFields} is
|
||||
* {@code true}, undocumented fields will be ignored and will not trigger a failure.
|
||||
*
|
||||
* @param subsectionExtractor the path identifying the subsection of the payload to
|
||||
* document
|
||||
* @param descriptors the descriptors
|
||||
* @param attributes the additional attributes
|
||||
* @param ignoreUndocumentedFields whether undocumented fields should be ignored
|
||||
* @since 1.2.0
|
||||
*/
|
||||
protected RequestFieldsSnippet(PayloadSubsectionExtractor<?> subsectionExtractor,
|
||||
List<FieldDescriptor> descriptors, Map<String, Object> attributes,
|
||||
boolean ignoreUndocumentedFields) {
|
||||
super("request", descriptors, attributes, ignoreUndocumentedFields,
|
||||
subsectionExtractor);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -137,8 +204,8 @@ public class RequestFieldsSnippet extends AbstractFieldsSnippet {
|
||||
FieldDescriptor... additionalDescriptors) {
|
||||
List<FieldDescriptor> combinedDescriptors = new ArrayList<>();
|
||||
combinedDescriptors.addAll(getFieldDescriptors());
|
||||
combinedDescriptors.addAll(
|
||||
PayloadDocumentation.applyPathPrefix(pathPrefix, Arrays.asList(additionalDescriptors)));
|
||||
combinedDescriptors.addAll(PayloadDocumentation.applyPathPrefix(pathPrefix,
|
||||
Arrays.asList(additionalDescriptors)));
|
||||
return new RequestFieldsSnippet(combinedDescriptors, this.getAttributes());
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ import org.springframework.restdocs.snippet.SnippetException;
|
||||
*
|
||||
* @author Mathieu Pousse
|
||||
* @author Andy Wilkinson
|
||||
* @since 1.2.0
|
||||
* @see PayloadDocumentation#requestPartFields(String, FieldDescriptor...)
|
||||
* @see PayloadDocumentation#requestPartFields(String, List)
|
||||
*/
|
||||
@@ -97,8 +98,81 @@ public class RequestPartFieldsSnippet extends AbstractFieldsSnippet {
|
||||
*/
|
||||
protected RequestPartFieldsSnippet(String partName, List<FieldDescriptor> descriptors,
|
||||
Map<String, Object> attributes, boolean ignoreUndocumentedFields) {
|
||||
this(partName, null, descriptors, attributes, ignoreUndocumentedFields);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@code RequestPartFieldsSnippet} that will document the fields in a
|
||||
* subsection of the request part using the given {@code descriptors}. The subsection
|
||||
* will be extracted using the given {@code subsectionExtractor}. Undocumented fields
|
||||
* will trigger a failure.
|
||||
*
|
||||
* @param partName the part name
|
||||
* @param subsectionExtractor the subsection extractor
|
||||
* @param descriptors the descriptors
|
||||
*/
|
||||
protected RequestPartFieldsSnippet(String partName,
|
||||
PayloadSubsectionExtractor<?> subsectionExtractor,
|
||||
List<FieldDescriptor> descriptors) {
|
||||
this(partName, subsectionExtractor, descriptors, null, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@code RequestPartFieldsSnippet} that will document the fields in a
|
||||
* subsection the request part using the given {@code descriptors}. The subsection
|
||||
* will be extracted using the given {@code subsectionExtractor}. If
|
||||
* {@code ignoreUndocumentedFields} is {@code true}, undocumented fields will be
|
||||
* ignored and will not trigger a failure.
|
||||
*
|
||||
* @param partName the part name
|
||||
* @param subsectionExtractor the subsection extractor
|
||||
* @param descriptors the descriptors
|
||||
* @param ignoreUndocumentedFields whether undocumented fields should be ignored
|
||||
*/
|
||||
protected RequestPartFieldsSnippet(String partName,
|
||||
PayloadSubsectionExtractor<?> subsectionExtractor,
|
||||
List<FieldDescriptor> descriptors, boolean ignoreUndocumentedFields) {
|
||||
this(partName, subsectionExtractor, descriptors, null, ignoreUndocumentedFields);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@code RequestPartFieldsSnippet} that will document the fields in a
|
||||
* subsection of the request part using the given {@code descriptors}. The subsection
|
||||
* will be extracted using the given {@code subsectionExtractor}. The given
|
||||
* {@code attributes} will be included in the model during template rendering.
|
||||
* Undocumented fields will trigger a failure.
|
||||
*
|
||||
* @param partName the part name
|
||||
* @param subsectionExtractor the subsection extractor
|
||||
* @param descriptors the descriptors
|
||||
* @param attributes the additional attributes
|
||||
*/
|
||||
protected RequestPartFieldsSnippet(String partName,
|
||||
PayloadSubsectionExtractor<?> subsectionExtractor,
|
||||
List<FieldDescriptor> descriptors, Map<String, Object> attributes) {
|
||||
this(partName, subsectionExtractor, descriptors, attributes, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@code RequestPartFieldsSnippet} that will document the fields in a
|
||||
* subsection of the request part using the given {@code descriptors}. The subsection
|
||||
* will be extracted using the given {@code subsectionExtractor}. The given
|
||||
* {@code attributes} will be included in the model during template rendering. If
|
||||
* {@code ignoreUndocumentedFields} is {@code true}, undocumented fields will be
|
||||
* ignored and will not trigger a failure.
|
||||
*
|
||||
* @param partName the part name
|
||||
* @param subsectionExtractor the subsection extractor
|
||||
* @param descriptors the descriptors
|
||||
* @param attributes the additional attributes
|
||||
* @param ignoreUndocumentedFields whether undocumented fields should be ignored
|
||||
*/
|
||||
protected RequestPartFieldsSnippet(String partName,
|
||||
PayloadSubsectionExtractor<?> subsectionExtractor,
|
||||
List<FieldDescriptor> descriptors, Map<String, Object> attributes,
|
||||
boolean ignoreUndocumentedFields) {
|
||||
super("request-part-" + partName, "request-part", descriptors, attributes,
|
||||
ignoreUndocumentedFields);
|
||||
ignoreUndocumentedFields, subsectionExtractor);
|
||||
this.partName = partName;
|
||||
}
|
||||
|
||||
|
||||
@@ -87,7 +87,77 @@ public class ResponseFieldsSnippet extends AbstractFieldsSnippet {
|
||||
*/
|
||||
protected ResponseFieldsSnippet(List<FieldDescriptor> descriptors,
|
||||
Map<String, Object> attributes, boolean ignoreUndocumentedFields) {
|
||||
super("response", descriptors, attributes, ignoreUndocumentedFields);
|
||||
this(null, descriptors, attributes, ignoreUndocumentedFields);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@code ResponseFieldsSnippet} that will document the fields in a
|
||||
* subsection of the response using the given {@code descriptors}. The subsection will
|
||||
* be extracted using the given {@code subsectionExtractor}. Undocumented fields will
|
||||
* trigger a failure.
|
||||
*
|
||||
* @param subsectionExtractor the subsection extractor
|
||||
* @param descriptors the descriptors
|
||||
* @since 1.2.0
|
||||
*/
|
||||
protected ResponseFieldsSnippet(PayloadSubsectionExtractor<?> subsectionExtractor,
|
||||
List<FieldDescriptor> descriptors) {
|
||||
this(subsectionExtractor, descriptors, null, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@code ResponseFieldsSnippet} that will document the fields in the
|
||||
* subsection of the response using the given {@code descriptors}. The subsection will
|
||||
* be extracted using the given {@code subsectionExtractor}. If
|
||||
* {@code ignoreUndocumentedFields} is {@code true}, undocumented fields will be
|
||||
* ignored and will not trigger a failure.
|
||||
*
|
||||
* @param subsectionExtractor the subsection extractor
|
||||
* @param descriptors the descriptors
|
||||
* @param ignoreUndocumentedFields whether undocumented fields should be ignored
|
||||
* @since 1.2.0
|
||||
*/
|
||||
protected ResponseFieldsSnippet(PayloadSubsectionExtractor<?> subsectionExtractor,
|
||||
List<FieldDescriptor> descriptors, boolean ignoreUndocumentedFields) {
|
||||
this(subsectionExtractor, descriptors, null, ignoreUndocumentedFields);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@code ResponseFieldsSnippet} that will document the fields in a
|
||||
* subsection of the response using the given {@code descriptors}. The subsection will
|
||||
* be extracted using the given {@code subsectionExtractor}. The given
|
||||
* {@code attributes} will be included in the model during template rendering.
|
||||
* Undocumented fields will trigger a failure.
|
||||
*
|
||||
* @param subsectionExtractor the subsection extractor
|
||||
* @param descriptors the descriptors
|
||||
* @param attributes the additional attributes
|
||||
* @since 1.2.0
|
||||
*/
|
||||
protected ResponseFieldsSnippet(PayloadSubsectionExtractor<?> subsectionExtractor,
|
||||
List<FieldDescriptor> descriptors, Map<String, Object> attributes) {
|
||||
this(subsectionExtractor, descriptors, attributes, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@code ResponseFieldsSnippet} that will document the fields in a
|
||||
* subsection of the response using the given {@code descriptors}. The subsection will
|
||||
* be extracted using the given {@code subsectionExtractor}. The given
|
||||
* {@code attributes} will be included in the model during template rendering. If
|
||||
* {@code ignoreUndocumentedFields} is {@code true}, undocumented fields will be
|
||||
* ignored and will not trigger a failure.
|
||||
*
|
||||
* @param subsectionExtractor the subsection extractor
|
||||
* @param descriptors the descriptors
|
||||
* @param attributes the additional attributes
|
||||
* @param ignoreUndocumentedFields whether undocumented fields should be ignored
|
||||
* @since 1.2.0
|
||||
*/
|
||||
protected ResponseFieldsSnippet(PayloadSubsectionExtractor<?> subsectionExtractor,
|
||||
List<FieldDescriptor> descriptors, Map<String, Object> attributes,
|
||||
boolean ignoreUndocumentedFields) {
|
||||
super("response", descriptors, attributes, ignoreUndocumentedFields,
|
||||
subsectionExtractor);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -138,8 +208,8 @@ public class ResponseFieldsSnippet extends AbstractFieldsSnippet {
|
||||
FieldDescriptor... additionalDescriptors) {
|
||||
List<FieldDescriptor> combinedDescriptors = new ArrayList<>();
|
||||
combinedDescriptors.addAll(getFieldDescriptors());
|
||||
combinedDescriptors.addAll(
|
||||
PayloadDocumentation.applyPathPrefix(pathPrefix, Arrays.asList(additionalDescriptors)));
|
||||
combinedDescriptors.addAll(PayloadDocumentation.applyPathPrefix(pathPrefix,
|
||||
Arrays.asList(additionalDescriptors)));
|
||||
return new ResponseFieldsSnippet(combinedDescriptors, this.getAttributes());
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright 2014-2016 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
|
||||
*
|
||||
* http://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.restdocs.payload;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonParseException;
|
||||
import com.fasterxml.jackson.databind.JsonMappingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
||||
import org.springframework.http.MediaType;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link FieldPathPayloadSubsectionExtractor}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class FieldPathPayloadSubsectionExtractorTests {
|
||||
|
||||
@Rule
|
||||
public final ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void extractMapSubsectionOfJsonMap()
|
||||
throws JsonParseException, JsonMappingException, IOException {
|
||||
byte[] extractedPayload = new FieldPathPayloadSubsectionExtractor("a.b")
|
||||
.extractSubsection("{\"a\":{\"b\":{\"c\":5}}}".getBytes(),
|
||||
MediaType.APPLICATION_JSON);
|
||||
Map<String, Object> extracted = new ObjectMapper().readValue(extractedPayload,
|
||||
Map.class);
|
||||
assertThat(extracted.size(), is(equalTo(1)));
|
||||
assertThat(extracted.get("c"), is(equalTo((Object) 5)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void extractMultiElementArraySubsectionOfJsonMap()
|
||||
throws JsonParseException, JsonMappingException, IOException {
|
||||
byte[] extractedPayload = new FieldPathPayloadSubsectionExtractor("a")
|
||||
.extractSubsection("{\"a\":[{\"b\":5},{\"b\":4}]}".getBytes(),
|
||||
MediaType.APPLICATION_JSON);
|
||||
List<Map<String, Object>> extracted = new ObjectMapper()
|
||||
.readValue(extractedPayload, List.class);
|
||||
assertThat(extracted.size(), is(equalTo(2)));
|
||||
assertThat(extracted.get(0).get("b"), is(equalTo((Object) 5)));
|
||||
assertThat(extracted.get(1).get("b"), is(equalTo((Object) 4)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void extractSingleElementArraySubsectionOfJsonMap()
|
||||
throws JsonParseException, JsonMappingException, IOException {
|
||||
byte[] extractedPayload = new FieldPathPayloadSubsectionExtractor("a.[]")
|
||||
.extractSubsection("{\"a\":[{\"b\":5}]}".getBytes(),
|
||||
MediaType.APPLICATION_JSON);
|
||||
List<Map<String, Object>> extracted = new ObjectMapper()
|
||||
.readValue(extractedPayload, List.class);
|
||||
assertThat(extracted.size(), is(equalTo(1)));
|
||||
assertThat(extracted.get(0).get("b"), is(equalTo((Object) 5)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void extractMapSubsectionFromSingleElementArrayInAJsonMap()
|
||||
throws JsonParseException, JsonMappingException, IOException {
|
||||
byte[] extractedPayload = new FieldPathPayloadSubsectionExtractor("a.[].b")
|
||||
.extractSubsection("{\"a\":[{\"b\":{\"c\":5}}]}".getBytes(),
|
||||
MediaType.APPLICATION_JSON);
|
||||
Map<String, Object> extracted = new ObjectMapper().readValue(extractedPayload,
|
||||
Map.class);
|
||||
assertThat(extracted.size(), is(equalTo(1)));
|
||||
assertThat(extracted.get("c"), is(equalTo((Object) 5)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void extractMapSubsectionFromMultiElementArrayInAJsonMap()
|
||||
throws JsonParseException, JsonMappingException, IOException {
|
||||
this.thrown.expect(PayloadHandlingException.class);
|
||||
this.thrown.expectMessage(
|
||||
equalTo("a.[].b does not uniquely identify a subsection of the payload"));
|
||||
new FieldPathPayloadSubsectionExtractor("a.[].b").extractSubsection(
|
||||
"{\"a\":[{\"b\":{\"c\":5}},{\"b\":{\"c\":6}}]}".getBytes(),
|
||||
MediaType.APPLICATION_JSON);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -33,7 +33,9 @@ import org.springframework.restdocs.templates.mustache.MustacheTemplateEngine;
|
||||
import static org.hamcrest.CoreMatchers.containsString;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.springframework.restdocs.payload.PayloadDocumentation.beneathPath;
|
||||
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
|
||||
import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields;
|
||||
import static org.springframework.restdocs.snippet.Attributes.attributes;
|
||||
import static org.springframework.restdocs.snippet.Attributes.key;
|
||||
|
||||
@@ -63,6 +65,19 @@ public class RequestFieldsSnippetTests extends AbstractSnippetTests {
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void subsectionOfMapRequest() throws IOException {
|
||||
this.snippets.expect("request-fields-beneath-a")
|
||||
.withContents(tableWithHeader("Path", "Type", "Description")
|
||||
.row("`b`", "`Number`", "one").row("`c`", "`String`", "two"));
|
||||
|
||||
requestFields(beneathPath("a"), fieldWithPath("b").description("one"),
|
||||
fieldWithPath("c").description("two"))
|
||||
.document(this.operationBuilder.request("http://localhost")
|
||||
.content("{\"a\": {\"b\": 5, \"c\": \"charlie\"}}")
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void arrayRequestWithFields() throws IOException {
|
||||
this.snippets.expectRequestFields()
|
||||
@@ -81,6 +96,19 @@ public class RequestFieldsSnippetTests extends AbstractSnippetTests {
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void subsectionOfArrayRequest() throws IOException {
|
||||
this.snippets.expect("request-fields-beneath-[].a")
|
||||
.withContents(tableWithHeader("Path", "Type", "Description")
|
||||
.row("`b`", "`Number`", "one").row("`c`", "`String`", "two"));
|
||||
|
||||
requestFields(beneathPath("[].a"), fieldWithPath("b").description("one"),
|
||||
fieldWithPath("c").description("two"))
|
||||
.document(this.operationBuilder.request("http://localhost")
|
||||
.content("[{\"a\": {\"b\": 5, \"c\": \"charlie\"}}]")
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ignoredRequestField() throws IOException {
|
||||
this.snippets.expectRequestFields()
|
||||
|
||||
@@ -26,6 +26,7 @@ import org.springframework.restdocs.AbstractSnippetTests;
|
||||
import org.springframework.restdocs.operation.Operation;
|
||||
import org.springframework.restdocs.templates.TemplateFormat;
|
||||
|
||||
import static org.springframework.restdocs.payload.PayloadDocumentation.beneathPath;
|
||||
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
|
||||
|
||||
/**
|
||||
@@ -60,6 +61,25 @@ public class RequestPartFieldsSnippetTests extends AbstractSnippetTests {
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mapRequestPartSubsectionFields() throws IOException {
|
||||
this.snippets.expect("request-part-one-fields-beneath-a")
|
||||
.withContents(tableWithHeader("Path", "Type", "Description")
|
||||
.row("`b`", "`Number`", "one").row("`c`", "`String`", "two"));
|
||||
|
||||
new RequestPartFieldsSnippet("one",
|
||||
beneathPath("a"), Arrays
|
||||
.asList(fieldWithPath("b").description("one"),
|
||||
fieldWithPath("c").description("two")))
|
||||
.document(
|
||||
this.operationBuilder
|
||||
.request("http://localhost")
|
||||
.part("one",
|
||||
"{\"a\": {\"b\": 5, \"c\": \"charlie\"}}"
|
||||
.getBytes())
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multipleRequestParts() throws IOException {
|
||||
this.snippets.expectRequestPartFields("one");
|
||||
|
||||
@@ -33,7 +33,9 @@ import org.springframework.restdocs.templates.mustache.MustacheTemplateEngine;
|
||||
import static org.hamcrest.CoreMatchers.containsString;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.springframework.restdocs.payload.PayloadDocumentation.beneathPath;
|
||||
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
|
||||
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
|
||||
import static org.springframework.restdocs.snippet.Attributes.attributes;
|
||||
import static org.springframework.restdocs.snippet.Attributes.key;
|
||||
|
||||
@@ -70,6 +72,18 @@ public class ResponseFieldsSnippetTests extends AbstractSnippetTests {
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void subsectionOfMapResponse() throws IOException {
|
||||
this.snippets.expect("response-fields-beneath-a")
|
||||
.withContents(tableWithHeader("Path", "Type", "Description")
|
||||
.row("`b`", "`Number`", "one").row("`c`", "`String`", "two"));
|
||||
responseFields(beneathPath("a"), fieldWithPath("b").description("one"),
|
||||
fieldWithPath("c").description("two"))
|
||||
.document(this.operationBuilder.response()
|
||||
.content("{\"a\": {\"b\": 5, \"c\": \"charlie\"}}")
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void arrayResponseWithFields() throws IOException {
|
||||
this.snippets.expectResponseFields()
|
||||
|
||||
Reference in New Issue
Block a user