From 8b039e5f816aa4fa40488baa7cf80ea0bd9bda03 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 12 Apr 2016 17:29:40 +0100 Subject: [PATCH] Add support for reusing a snippet to document common elements This commit updates all of the Snippet implementations that take one or more descriptors to provide an and method that can be used to create a new Snippet that has additional descriptors. Closes gh-168 --- .../docs/asciidoc/documenting-your-api.adoc | 39 +++++++++++++++++ .../test/java/com/example/SnippetReuse.java | 34 +++++++++++++++ .../example/mockmvc/MockMvcSnippetReuse.java | 43 +++++++++++++++++++ .../restassured/RestAssuredSnippetReuse.java | 43 +++++++++++++++++++ .../restdocs/headers/HeaderDocumentation.java | 11 ++--- .../headers/RequestHeadersSnippet.java | 19 +++++++- .../headers/ResponseHeadersSnippet.java | 19 +++++++- .../restdocs/http/HttpDocumentation.java | 12 +++--- .../hypermedia/HypermediaDocumentation.java | 12 +++--- .../restdocs/hypermedia/LinksSnippet.java | 15 +++++++ .../payload/PayloadDocumentation.java | 12 +++--- .../payload/RequestFieldsSnippet.java | 18 +++++++- .../payload/ResponseFieldsSnippet.java | 18 +++++++- .../request/AbstractParametersSnippet.java | 13 ++++++ .../request/PathParametersSnippet.java | 16 +++++++ .../request/RequestDocumentation.java | 13 +++--- .../request/RequestParametersSnippet.java | 16 +++++++ .../headers/RequestHeadersSnippetTests.java | 23 ++++++++++ .../headers/ResponseHeadersSnippetTests.java | 21 +++++++++ .../hypermedia/LinksSnippetTests.java | 12 ++++++ .../payload/RequestFieldsSnippetTests.java | 16 +++++++ .../payload/ResponseFieldsSnippetTests.java | 21 +++++++++ .../request/PathParametersSnippetTests.java | 13 ++++++ .../RequestParametersSnippetTests.java | 12 ++++++ 24 files changed, 435 insertions(+), 36 deletions(-) create mode 100644 docs/src/test/java/com/example/SnippetReuse.java create mode 100644 docs/src/test/java/com/example/mockmvc/MockMvcSnippetReuse.java create mode 100644 docs/src/test/java/com/example/restassured/RestAssuredSnippetReuse.java diff --git a/docs/src/docs/asciidoc/documenting-your-api.adoc b/docs/src/docs/asciidoc/documenting-your-api.adoc index f036275c..88313f97 100644 --- a/docs/src/docs/asciidoc/documenting-your-api.adoc +++ b/docs/src/docs/asciidoc/documenting-your-api.adoc @@ -445,6 +445,45 @@ When documenting HTTP Headers, the test will fail if a documented header is not the request or response. + +[[documenting-your-api-reusing-snippets]] +=== Reusing snippets + +It's common for an API that's being documented to have some features that are common +across several of its resources. To avoid repetition when documenting such resources a +`Snippet` configured with the common elements can be reused. + +First, create the `Snippet` that describes the common elements. For example: + +[source,java,indent=0] +---- +include::{examples-dir}/com/example/SnippetReuse.java[tags=field] +---- + +Second, use this snippet and add further descriptors that are resource-specific. For +example: + +[source,java,indent=0,role="primary"] +.MockMvc +---- +include::{examples-dir}/com/example/mockmvc/MockMvcSnippetReuse.java[tags=use] +---- +<1> Reuse the `pagingLinks` `Snippet` calling `and` to add descriptors that are specific + to the resource that is being documented. + +[source,java,indent=0,role="secondary"] +.REST Assured +---- +include::{examples-dir}/com/example/restassured/RestAssuredSnippetReuse.java[tags=use] +---- +<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 the rels `first`, `last`, `next`, `previous`, +`alpha`, and `bravo` are all documented. + + + [[documenting-your-api-constraints]] === Documenting constraints diff --git a/docs/src/test/java/com/example/SnippetReuse.java b/docs/src/test/java/com/example/SnippetReuse.java new file mode 100644 index 00000000..6ab40ddb --- /dev/null +++ b/docs/src/test/java/com/example/SnippetReuse.java @@ -0,0 +1,34 @@ +/* + * Copyright 2012-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 com.example; + +import org.springframework.restdocs.hypermedia.LinksSnippet; + +import static org.springframework.restdocs.hypermedia.HypermediaDocumentation.linkWithRel; +import static org.springframework.restdocs.hypermedia.HypermediaDocumentation.links; + +public class SnippetReuse { + + // tag::field[] + 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")); + // end::field[] + +} diff --git a/docs/src/test/java/com/example/mockmvc/MockMvcSnippetReuse.java b/docs/src/test/java/com/example/mockmvc/MockMvcSnippetReuse.java new file mode 100644 index 00000000..34dc3ae1 --- /dev/null +++ b/docs/src/test/java/com/example/mockmvc/MockMvcSnippetReuse.java @@ -0,0 +1,43 @@ +/* + * Copyright 2012-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 com.example.mockmvc; + +import com.example.SnippetReuse; + +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; + +import static org.springframework.restdocs.hypermedia.HypermediaDocumentation.linkWithRel; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +public class MockMvcSnippetReuse extends SnippetReuse { + + private MockMvc mockMvc; + + public void documentation() throws Exception { + // tag::use[] + 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")))); + // end::use[] + } + +} diff --git a/docs/src/test/java/com/example/restassured/RestAssuredSnippetReuse.java b/docs/src/test/java/com/example/restassured/RestAssuredSnippetReuse.java new file mode 100644 index 00000000..c792a7fb --- /dev/null +++ b/docs/src/test/java/com/example/restassured/RestAssuredSnippetReuse.java @@ -0,0 +1,43 @@ +/* + * Copyright 2012-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 com.example.restassured; + +import com.example.SnippetReuse; +import com.jayway.restassured.RestAssured; +import com.jayway.restassured.specification.RequestSpecification; + + +import static org.hamcrest.CoreMatchers.is; +import static org.springframework.restdocs.hypermedia.HypermediaDocumentation.linkWithRel; +import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.document; + +public class RestAssuredSnippetReuse extends SnippetReuse { + + private RequestSpecification spec; + + public void documentation() throws Exception { + // tag::use[] + 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)); + // end::use[] + } + +} diff --git a/spring-restdocs-core/src/main/java/org/springframework/restdocs/headers/HeaderDocumentation.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/headers/HeaderDocumentation.java index 85800ecf..1eb4f0f9 100644 --- a/spring-restdocs-core/src/main/java/org/springframework/restdocs/headers/HeaderDocumentation.java +++ b/spring-restdocs-core/src/main/java/org/springframework/restdocs/headers/HeaderDocumentation.java @@ -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. @@ -55,7 +55,7 @@ public abstract class HeaderDocumentation { * @return the snippet that will document the request headers * @see #headerWithName(String) */ - public static Snippet requestHeaders(HeaderDescriptor... descriptors) { + public static RequestHeadersSnippet requestHeaders(HeaderDescriptor... descriptors) { return new RequestHeadersSnippet(Arrays.asList(descriptors)); } @@ -72,7 +72,7 @@ public abstract class HeaderDocumentation { * @return the snippet that will document the request headers * @see #headerWithName(String) */ - public static Snippet requestHeaders(Map attributes, + public static RequestHeadersSnippet requestHeaders(Map attributes, HeaderDescriptor... descriptors) { return new RequestHeadersSnippet(Arrays.asList(descriptors), attributes); } @@ -88,7 +88,8 @@ public abstract class HeaderDocumentation { * @return the snippet that will document the response headers * @see #headerWithName(String) */ - public static Snippet responseHeaders(HeaderDescriptor... descriptors) { + public static ResponseHeadersSnippet responseHeaders( + HeaderDescriptor... descriptors) { return new ResponseHeadersSnippet(Arrays.asList(descriptors)); } @@ -106,7 +107,7 @@ public abstract class HeaderDocumentation { * @return the snippet that will document the response headers * @see #headerWithName(String) */ - public static Snippet responseHeaders(Map attributes, + public static ResponseHeadersSnippet responseHeaders(Map attributes, HeaderDescriptor... descriptors) { return new ResponseHeadersSnippet(Arrays.asList(descriptors), attributes); } diff --git a/spring-restdocs-core/src/main/java/org/springframework/restdocs/headers/RequestHeadersSnippet.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/headers/RequestHeadersSnippet.java index 83dd6b6d..ecdc933a 100644 --- a/spring-restdocs-core/src/main/java/org/springframework/restdocs/headers/RequestHeadersSnippet.java +++ b/spring-restdocs-core/src/main/java/org/springframework/restdocs/headers/RequestHeadersSnippet.java @@ -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. @@ -16,6 +16,8 @@ package org.springframework.restdocs.headers; +import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Set; @@ -27,6 +29,7 @@ import org.springframework.restdocs.snippet.Snippet; * A {@link Snippet} that documents the headers in a request. * * @author Andreas Evers + * @author Andy Wilkinson * @see HeaderDocumentation#requestHeaders(HeaderDescriptor...) * @see HeaderDocumentation#requestHeaders(Map, HeaderDescriptor...) */ @@ -60,4 +63,18 @@ public class RequestHeadersSnippet extends AbstractHeadersSnippet { return operation.getRequest().getHeaders().keySet(); } + /** + * Returns a new {@code RequestHeadersSnippet} configured with this snippet's + * attributes and its descriptors combined with the given + * {@code additionalDescriptors}. + * @param additionalDescriptors the additional descriptors + * @return the new snippet + */ + public RequestHeadersSnippet and(HeaderDescriptor... additionalDescriptors) { + List combinedDescriptors = new ArrayList<>(); + combinedDescriptors.addAll(this.getHeaderDescriptors()); + combinedDescriptors.addAll(Arrays.asList(additionalDescriptors)); + return new RequestHeadersSnippet(combinedDescriptors, getAttributes()); + } + } diff --git a/spring-restdocs-core/src/main/java/org/springframework/restdocs/headers/ResponseHeadersSnippet.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/headers/ResponseHeadersSnippet.java index 979083c4..1a417167 100644 --- a/spring-restdocs-core/src/main/java/org/springframework/restdocs/headers/ResponseHeadersSnippet.java +++ b/spring-restdocs-core/src/main/java/org/springframework/restdocs/headers/ResponseHeadersSnippet.java @@ -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. @@ -16,6 +16,8 @@ package org.springframework.restdocs.headers; +import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Set; @@ -27,6 +29,7 @@ import org.springframework.restdocs.snippet.Snippet; * A {@link Snippet} that documents the headers in a response. * * @author Andreas Evers + * @author Andy Wilkinson * @see HeaderDocumentation#responseHeaders(HeaderDescriptor...) * @see HeaderDocumentation#responseHeaders(Map, HeaderDescriptor...) */ @@ -60,4 +63,18 @@ public class ResponseHeadersSnippet extends AbstractHeadersSnippet { return operation.getResponse().getHeaders().keySet(); } + /** + * Returns a new {@code ResponseHeadersSnippet} configured with this snippet's + * attributes and its descriptors combined with the given + * {@code additionalDescriptors}. + * @param additionalDescriptors the additional descriptors + * @return the new snippet + */ + public final ResponseHeadersSnippet and(HeaderDescriptor... additionalDescriptors) { + List combinedDescriptors = new ArrayList<>(); + combinedDescriptors.addAll(this.getHeaderDescriptors()); + combinedDescriptors.addAll(Arrays.asList(additionalDescriptors)); + return new ResponseHeadersSnippet(combinedDescriptors, getAttributes()); + } + } diff --git a/spring-restdocs-core/src/main/java/org/springframework/restdocs/http/HttpDocumentation.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/http/HttpDocumentation.java index f1bc8b38..5d872fe2 100644 --- a/spring-restdocs-core/src/main/java/org/springframework/restdocs/http/HttpDocumentation.java +++ b/spring-restdocs-core/src/main/java/org/springframework/restdocs/http/HttpDocumentation.java @@ -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. @@ -18,8 +18,6 @@ package org.springframework.restdocs.http; import java.util.Map; -import org.springframework.restdocs.snippet.Snippet; - /** * Static factory methods for documenting a RESTful API's HTTP requests. * @@ -38,7 +36,7 @@ public abstract class HttpDocumentation { * * @return the snippet that will document the HTTP request */ - public static Snippet httpRequest() { + public static HttpRequestSnippet httpRequest() { return new HttpRequestSnippet(); } @@ -50,7 +48,7 @@ public abstract class HttpDocumentation { * @param attributes the attributes * @return the snippet that will document the HTTP request */ - public static Snippet httpRequest(Map attributes) { + public static HttpRequestSnippet httpRequest(Map attributes) { return new HttpRequestSnippet(attributes); } @@ -60,7 +58,7 @@ public abstract class HttpDocumentation { * * @return the snippet that will document the HTTP response */ - public static Snippet httpResponse() { + public static HttpResponseSnippet httpResponse() { return new HttpResponseSnippet(); } @@ -72,7 +70,7 @@ public abstract class HttpDocumentation { * @param attributes the attributes * @return the snippet that will document the HTTP response */ - public static Snippet httpResponse(Map attributes) { + public static HttpResponseSnippet httpResponse(Map attributes) { return new HttpResponseSnippet(attributes); } diff --git a/spring-restdocs-core/src/main/java/org/springframework/restdocs/hypermedia/HypermediaDocumentation.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/hypermedia/HypermediaDocumentation.java index d5ddaf0b..c2f11b75 100644 --- a/spring-restdocs-core/src/main/java/org/springframework/restdocs/hypermedia/HypermediaDocumentation.java +++ b/spring-restdocs-core/src/main/java/org/springframework/restdocs/hypermedia/HypermediaDocumentation.java @@ -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. @@ -19,8 +19,6 @@ package org.springframework.restdocs.hypermedia; import java.util.Arrays; import java.util.Map; -import org.springframework.restdocs.snippet.Snippet; - /** * Static factory methods for documenting a RESTful API that utilizes Hypermedia. * @@ -59,7 +57,7 @@ public abstract class HypermediaDocumentation { * @param descriptors the descriptions of the response's links * @return the snippet that will document the links */ - public static Snippet links(LinkDescriptor... descriptors) { + public static LinksSnippet links(LinkDescriptor... descriptors) { return new LinksSnippet(new ContentTypeLinkExtractor(), Arrays.asList(descriptors)); } @@ -83,7 +81,7 @@ public abstract class HypermediaDocumentation { * @param descriptors the descriptions of the response's links * @return the snippet that will document the links */ - public static Snippet links(Map attributes, + public static LinksSnippet links(Map attributes, LinkDescriptor... descriptors) { return new LinksSnippet(new ContentTypeLinkExtractor(), Arrays.asList(descriptors), attributes); @@ -107,7 +105,7 @@ public abstract class HypermediaDocumentation { * @param descriptors the descriptions of the response's links * @return the snippet that will document the links */ - public static Snippet links(LinkExtractor linkExtractor, + public static LinksSnippet links(LinkExtractor linkExtractor, LinkDescriptor... descriptors) { return new LinksSnippet(linkExtractor, Arrays.asList(descriptors)); } @@ -132,7 +130,7 @@ public abstract class HypermediaDocumentation { * @param descriptors the descriptions of the response's links * @return the snippet that will document the links */ - public static Snippet links(LinkExtractor linkExtractor, + public static LinksSnippet links(LinkExtractor linkExtractor, Map attributes, LinkDescriptor... descriptors) { return new LinksSnippet(linkExtractor, Arrays.asList(descriptors), attributes); } diff --git a/spring-restdocs-core/src/main/java/org/springframework/restdocs/hypermedia/LinksSnippet.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/hypermedia/LinksSnippet.java index 771e2e7a..7c684ba9 100644 --- a/spring-restdocs-core/src/main/java/org/springframework/restdocs/hypermedia/LinksSnippet.java +++ b/spring-restdocs-core/src/main/java/org/springframework/restdocs/hypermedia/LinksSnippet.java @@ -18,6 +18,7 @@ package org.springframework.restdocs.hypermedia; import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; @@ -170,4 +171,18 @@ public class LinksSnippet extends TemplatedSnippet { return model; } + /** + * Returns a new {@code RequestHeadersSnippet} configured with this snippet's link + * extractor and attributes, and its descriptors combined with the given + * {@code additionalDescriptors}. + * @param additionalDescriptors the additional descriptors + * @return the new snippet + */ + public LinksSnippet and(LinkDescriptor... additionalDescriptors) { + List combinedDescriptors = new ArrayList<>(); + combinedDescriptors.addAll(this.descriptorsByRel.values()); + combinedDescriptors.addAll(Arrays.asList(additionalDescriptors)); + return new LinksSnippet(this.linkExtractor, combinedDescriptors, getAttributes()); + } + } diff --git a/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/PayloadDocumentation.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/PayloadDocumentation.java index 097e1c47..f2391277 100644 --- a/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/PayloadDocumentation.java +++ b/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/PayloadDocumentation.java @@ -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. @@ -19,8 +19,6 @@ package org.springframework.restdocs.payload; import java.util.Arrays; import java.util.Map; -import org.springframework.restdocs.snippet.Snippet; - /** * Static factory methods for documenting a RESTful API's request and response payloads. * @@ -117,7 +115,7 @@ public abstract class PayloadDocumentation { * @return the snippet that will document the fields * @see #fieldWithPath(String) */ - public static Snippet requestFields(FieldDescriptor... descriptors) { + public static RequestFieldsSnippet requestFields(FieldDescriptor... descriptors) { return new RequestFieldsSnippet(Arrays.asList(descriptors)); } @@ -142,7 +140,7 @@ public abstract class PayloadDocumentation { * @return the snippet that will document the fields * @see #fieldWithPath(String) */ - public static Snippet requestFields(Map attributes, + public static RequestFieldsSnippet requestFields(Map attributes, FieldDescriptor... descriptors) { return new RequestFieldsSnippet(Arrays.asList(descriptors), attributes); } @@ -167,7 +165,7 @@ public abstract class PayloadDocumentation { * @return the snippet that will document the fields * @see #fieldWithPath(String) */ - public static Snippet responseFields(FieldDescriptor... descriptors) { + public static ResponseFieldsSnippet responseFields(FieldDescriptor... descriptors) { return new ResponseFieldsSnippet(Arrays.asList(descriptors)); } @@ -192,7 +190,7 @@ public abstract class PayloadDocumentation { * @return the snippet that will document the fields * @see #fieldWithPath(String) */ - public static Snippet responseFields(Map attributes, + public static ResponseFieldsSnippet responseFields(Map attributes, FieldDescriptor... descriptors) { return new ResponseFieldsSnippet(Arrays.asList(descriptors), attributes); } diff --git a/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/RequestFieldsSnippet.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/RequestFieldsSnippet.java index 354a0283..fdc3e609 100644 --- a/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/RequestFieldsSnippet.java +++ b/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/RequestFieldsSnippet.java @@ -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. @@ -17,6 +17,8 @@ package org.springframework.restdocs.payload; import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Map; @@ -66,4 +68,18 @@ public class RequestFieldsSnippet extends AbstractFieldsSnippet { return operation.getRequest().getContent(); } + /** + * Returns a new {@code RequestFieldsSnippet} configured with this snippet's + * attributes and its descriptors combined with the given + * {@code additionalDescriptors}. + * @param additionalDescriptors the additional descriptors + * @return the new snippet + */ + public RequestFieldsSnippet and(FieldDescriptor... additionalDescriptors) { + List combinedDescriptors = new ArrayList<>(); + combinedDescriptors.addAll(getFieldDescriptors()); + combinedDescriptors.addAll(Arrays.asList(additionalDescriptors)); + return new RequestFieldsSnippet(combinedDescriptors, this.getAttributes()); + } + } diff --git a/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/ResponseFieldsSnippet.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/ResponseFieldsSnippet.java index 82015ef8..14d5dd55 100644 --- a/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/ResponseFieldsSnippet.java +++ b/spring-restdocs-core/src/main/java/org/springframework/restdocs/payload/ResponseFieldsSnippet.java @@ -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. @@ -17,6 +17,8 @@ package org.springframework.restdocs.payload; import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Map; @@ -66,4 +68,18 @@ public class ResponseFieldsSnippet extends AbstractFieldsSnippet { return operation.getResponse().getContent(); } + /** + * Returns a new {@code ResponseFieldsSnippet} configured with this snippet's + * attributes and its descriptors combined with the given + * {@code additionalDescriptors}. + * @param additionalDescriptors the additional descriptors + * @return the new snippet + */ + public ResponseFieldsSnippet and(FieldDescriptor... additionalDescriptors) { + List combinedDescriptors = new ArrayList<>(); + combinedDescriptors.addAll(getFieldDescriptors()); + combinedDescriptors.addAll(Arrays.asList(additionalDescriptors)); + return new ResponseFieldsSnippet(combinedDescriptors, this.getAttributes()); + } + } diff --git a/spring-restdocs-core/src/main/java/org/springframework/restdocs/request/AbstractParametersSnippet.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/request/AbstractParametersSnippet.java index 0be93022..21d900fe 100644 --- a/spring-restdocs-core/src/main/java/org/springframework/restdocs/request/AbstractParametersSnippet.java +++ b/spring-restdocs-core/src/main/java/org/springframework/restdocs/request/AbstractParametersSnippet.java @@ -122,11 +122,24 @@ public abstract class AbstractParametersSnippet extends TemplatedSnippet { * {@link ParameterDescriptor#getName()}. * * @return the map of path descriptors + * @deprecated since 1.1.0 in favor of {@link #getParameterDescriptors()} */ + @Deprecated protected final Map getFieldDescriptors() { return this.descriptorsByName; } + /** + * Returns a {@code Map} of {@link ParameterDescriptor ParameterDescriptors} that will + * be used to generate the documentation key by their + * {@link ParameterDescriptor#getName()}. + * + * @return the map of path descriptors + */ + protected final Map getParameterDescriptors() { + return this.descriptorsByName; + } + /** * Returns a model for the given {@code descriptor}. * diff --git a/spring-restdocs-core/src/main/java/org/springframework/restdocs/request/PathParametersSnippet.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/request/PathParametersSnippet.java index 77cc1b4d..01ef25e4 100644 --- a/spring-restdocs-core/src/main/java/org/springframework/restdocs/request/PathParametersSnippet.java +++ b/spring-restdocs-core/src/main/java/org/springframework/restdocs/request/PathParametersSnippet.java @@ -16,6 +16,8 @@ package org.springframework.restdocs.request; +import java.util.ArrayList; +import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -122,4 +124,18 @@ public class PathParametersSnippet extends AbstractParametersSnippet { throw new SnippetException(message); } + /** + * Returns a new {@code PathParametersSnippet} configured with this snippet's + * attributes and its descriptors combined with the given + * {@code additionalDescriptors}. + * @param additionalDescriptors the additional descriptors + * @return the new snippet + */ + public PathParametersSnippet and(ParameterDescriptor... additionalDescriptors) { + List combinedDescriptors = new ArrayList<>(); + combinedDescriptors.addAll(getParameterDescriptors().values()); + combinedDescriptors.addAll(Arrays.asList(additionalDescriptors)); + return new PathParametersSnippet(combinedDescriptors, this.getAttributes()); + } + } diff --git a/spring-restdocs-core/src/main/java/org/springframework/restdocs/request/RequestDocumentation.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/request/RequestDocumentation.java index e0aa2f4b..6fa64c9b 100644 --- a/spring-restdocs-core/src/main/java/org/springframework/restdocs/request/RequestDocumentation.java +++ b/spring-restdocs-core/src/main/java/org/springframework/restdocs/request/RequestDocumentation.java @@ -20,7 +20,6 @@ import java.util.Arrays; import java.util.Map; import org.springframework.restdocs.operation.OperationRequest; -import org.springframework.restdocs.snippet.Snippet; /** * Static factory methods for documenting aspects of a request sent to a RESTful API. @@ -61,7 +60,8 @@ public abstract class RequestDocumentation { * @param descriptors the descriptions of the parameters in the request's path * @return the snippet that will document the parameters */ - public static Snippet pathParameters(ParameterDescriptor... descriptors) { + public static PathParametersSnippet pathParameters( + ParameterDescriptor... descriptors) { return new PathParametersSnippet(Arrays.asList(descriptors)); } @@ -84,7 +84,7 @@ public abstract class RequestDocumentation { * @param descriptors the descriptions of the parameters in the request's path * @return the snippet that will document the parameters */ - public static Snippet pathParameters(Map attributes, + public static PathParametersSnippet pathParameters(Map attributes, ParameterDescriptor... descriptors) { return new PathParametersSnippet(Arrays.asList(descriptors), attributes); } @@ -107,7 +107,8 @@ public abstract class RequestDocumentation { * @return the snippet * @see OperationRequest#getParameters() */ - public static Snippet requestParameters(ParameterDescriptor... descriptors) { + public static RequestParametersSnippet requestParameters( + ParameterDescriptor... descriptors) { return new RequestParametersSnippet(Arrays.asList(descriptors)); } @@ -131,8 +132,8 @@ public abstract class RequestDocumentation { * @return the snippet that will document the parameters * @see OperationRequest#getParameters() */ - public static Snippet requestParameters(Map attributes, - ParameterDescriptor... descriptors) { + public static RequestParametersSnippet requestParameters( + Map attributes, ParameterDescriptor... descriptors) { return new RequestParametersSnippet(Arrays.asList(descriptors), attributes); } diff --git a/spring-restdocs-core/src/main/java/org/springframework/restdocs/request/RequestParametersSnippet.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/request/RequestParametersSnippet.java index 5b1f9ba8..e85423fc 100644 --- a/spring-restdocs-core/src/main/java/org/springframework/restdocs/request/RequestParametersSnippet.java +++ b/spring-restdocs-core/src/main/java/org/springframework/restdocs/request/RequestParametersSnippet.java @@ -16,6 +16,8 @@ package org.springframework.restdocs.request; +import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Set; @@ -84,4 +86,18 @@ public class RequestParametersSnippet extends AbstractParametersSnippet { return operation.getRequest().getParameters().keySet(); } + /** + * Returns a new {@code RequestParametersSnippet} configured with this snippet's + * attributes and its descriptors combined with the given + * {@code additionalDescriptors}. + * @param additionalDescriptors the additional descriptors + * @return the new snippet + */ + public RequestParametersSnippet and(ParameterDescriptor... additionalDescriptors) { + List combinedDescriptors = new ArrayList<>(); + combinedDescriptors.addAll(getParameterDescriptors().values()); + combinedDescriptors.addAll(Arrays.asList(additionalDescriptors)); + return new RequestParametersSnippet(combinedDescriptors, this.getAttributes()); + } + } diff --git a/spring-restdocs-core/src/test/java/org/springframework/restdocs/headers/RequestHeadersSnippetTests.java b/spring-restdocs-core/src/test/java/org/springframework/restdocs/headers/RequestHeadersSnippetTests.java index fb13925a..59441562 100644 --- a/spring-restdocs-core/src/test/java/org/springframework/restdocs/headers/RequestHeadersSnippetTests.java +++ b/spring-restdocs-core/src/test/java/org/springframework/restdocs/headers/RequestHeadersSnippetTests.java @@ -143,4 +143,27 @@ public class RequestHeadersSnippetTests extends AbstractSnippetTests { .header("Accept", "*/*").build()); } + @Test + public void additionalDescriptors() throws IOException { + this.snippet.expectRequestHeaders("additional-descriptors") + .withContents(tableWithHeader("Name", "Description").row("X-Test", "one") + .row("Accept", "two").row("Accept-Encoding", "three") + .row("Accept-Language", "four").row("Cache-Control", "five") + .row("Connection", "six")); + HeaderDocumentation + .requestHeaders(headerWithName("X-Test").description("one"), + headerWithName("Accept").description("two"), + headerWithName("Accept-Encoding").description("three"), + headerWithName("Accept-Language").description("four")) + .and(headerWithName("Cache-Control").description("five"), + headerWithName("Connection").description("six")) + .document(operationBuilder("additional-descriptors") + .request("http://localhost").header("X-Test", "test") + .header("Accept", "*/*") + .header("Accept-Encoding", "gzip, deflate") + .header("Accept-Language", "en-US,en;q=0.5") + .header("Cache-Control", "max-age=0") + .header("Connection", "keep-alive").build()); + } + } diff --git a/spring-restdocs-core/src/test/java/org/springframework/restdocs/headers/ResponseHeadersSnippetTests.java b/spring-restdocs-core/src/test/java/org/springframework/restdocs/headers/ResponseHeadersSnippetTests.java index 6e16402b..d3f2ffbd 100644 --- a/spring-restdocs-core/src/test/java/org/springframework/restdocs/headers/ResponseHeadersSnippetTests.java +++ b/spring-restdocs-core/src/test/java/org/springframework/restdocs/headers/ResponseHeadersSnippetTests.java @@ -133,4 +133,25 @@ public class ResponseHeadersSnippetTests extends AbstractSnippetTests { .header("Etag", "lskjadldj3ii32l2ij23").build()); } + @Test + public void additionalDescriptors() throws IOException { + this.snippet.expectResponseHeaders("additional-descriptors") + .withContents(tableWithHeader("Name", "Description").row("X-Test", "one") + .row("Content-Type", "two").row("Etag", "three") + .row("Cache-Control", "five").row("Vary", "six")); + HeaderDocumentation + .responseHeaders(headerWithName("X-Test").description("one"), + headerWithName("Content-Type").description("two"), + headerWithName("Etag").description("three")) + .and(headerWithName("Cache-Control").description("five"), + headerWithName("Vary") + .description("six")) + .document(operationBuilder("additional-descriptors").response() + .header("X-Test", "test") + .header("Content-Type", "application/json") + .header("Etag", "lskjadldj3ii32l2ij23") + .header("Cache-Control", "max-age=0").header("Vary", "User-Agent") + .build()); + } + } diff --git a/spring-restdocs-core/src/test/java/org/springframework/restdocs/hypermedia/LinksSnippetTests.java b/spring-restdocs-core/src/test/java/org/springframework/restdocs/hypermedia/LinksSnippetTests.java index b0410976..b78b3b67 100644 --- a/spring-restdocs-core/src/test/java/org/springframework/restdocs/hypermedia/LinksSnippetTests.java +++ b/spring-restdocs-core/src/test/java/org/springframework/restdocs/hypermedia/LinksSnippetTests.java @@ -132,4 +132,16 @@ public class LinksSnippetTests extends AbstractSnippetTests { .build()); } + @Test + public void additionalDescriptors() throws IOException { + this.snippet.expectLinks("additional-descriptors") + .withContents(tableWithHeader("Relation", "Description").row("a", "one") + .row("b", "two")); + HypermediaDocumentation + .links(new StubLinkExtractor().withLinks(new Link("a", "alpha"), + new Link("b", "bravo")), + new LinkDescriptor("a").description("one")) + .and(new LinkDescriptor("b").description("two")) + .document(operationBuilder("additional-descriptors").build()); + } } diff --git a/spring-restdocs-core/src/test/java/org/springframework/restdocs/payload/RequestFieldsSnippetTests.java b/spring-restdocs-core/src/test/java/org/springframework/restdocs/payload/RequestFieldsSnippetTests.java index 94838367..195ed58a 100644 --- a/spring-restdocs-core/src/test/java/org/springframework/restdocs/payload/RequestFieldsSnippetTests.java +++ b/spring-restdocs-core/src/test/java/org/springframework/restdocs/payload/RequestFieldsSnippetTests.java @@ -160,4 +160,20 @@ public class RequestFieldsSnippetTests extends AbstractSnippetTests { .build()); } + @Test + public void additionalDescriptors() throws IOException { + this.snippet.expectRequestFields("additional-descriptors") + .withContents(tableWithHeader("Path", "Type", "Description") + .row("a.b", "Number", "one").row("a.c", "String", "two") + .row("a", "Object", "three")); + + PayloadDocumentation + .requestFields(fieldWithPath("a.b").description("one"), + fieldWithPath("a.c").description("two")) + .and(fieldWithPath("a").description("three")) + .document(operationBuilder("additional-descriptors") + .request("http://localhost") + .content("{\"a\": {\"b\": 5, \"c\": \"charlie\"}}").build()); + } + } diff --git a/spring-restdocs-core/src/test/java/org/springframework/restdocs/payload/ResponseFieldsSnippetTests.java b/spring-restdocs-core/src/test/java/org/springframework/restdocs/payload/ResponseFieldsSnippetTests.java index 4d996699..8e33fada 100644 --- a/spring-restdocs-core/src/test/java/org/springframework/restdocs/payload/ResponseFieldsSnippetTests.java +++ b/spring-restdocs-core/src/test/java/org/springframework/restdocs/payload/ResponseFieldsSnippetTests.java @@ -211,4 +211,25 @@ public class ResponseFieldsSnippetTests extends AbstractSnippetTests { .build()); } + @Test + public void additionalDescriptors() throws IOException { + this.snippet.expectResponseFields("additional-descriptors") + .withContents(tableWithHeader("Path", "Type", "Description") + .row("id", "Number", "one").row("date", "String", "two") + .row("assets", "Array", "three").row("assets[]", "Object", "four") + .row("assets[].id", "Number", "five") + .row("assets[].name", "String", "six")); + PayloadDocumentation + .responseFields(fieldWithPath("id").description("one"), + fieldWithPath("date").description("two"), + fieldWithPath("assets").description("three")) + .and(fieldWithPath("assets[]").description("four"), + fieldWithPath("assets[].id").description("five"), + fieldWithPath("assets[].name").description("six")) + .document(operationBuilder("additional-descriptors").response() + .content("{\"id\": 67,\"date\": \"2015-01-20\",\"assets\":" + + " [{\"id\":356,\"name\": \"sample\"}]}") + .build()); + } + } diff --git a/spring-restdocs-core/src/test/java/org/springframework/restdocs/request/PathParametersSnippetTests.java b/spring-restdocs-core/src/test/java/org/springframework/restdocs/request/PathParametersSnippetTests.java index 1b50d3d1..fb28e1cd 100644 --- a/spring-restdocs-core/src/test/java/org/springframework/restdocs/request/PathParametersSnippetTests.java +++ b/spring-restdocs-core/src/test/java/org/springframework/restdocs/request/PathParametersSnippetTests.java @@ -133,6 +133,19 @@ public class PathParametersSnippetTests extends AbstractSnippetTests { .build()); } + @Test + public void additionalDescriptors() throws IOException { + this.snippet.expectPathParameters("additional-descriptors").withContents( + tableWithTitleAndHeader(getTitle(), "Parameter", "Description") + .row("a", "one").row("b", "two")); + RequestDocumentation.pathParameters(parameterWithName("a").description("one")) + .and(parameterWithName("b").description("two")) + .document(operationBuilder("additional-descriptors") + .attribute(RestDocumentationGenerator.ATTRIBUTE_NAME_URL_TEMPLATE, + "/{a}/{b}") + .build()); + } + private String getTitle() { return this.templateFormat == TemplateFormats.asciidoctor() ? "/{a}/{b}" : "`/{a}/{b}`"; diff --git a/spring-restdocs-core/src/test/java/org/springframework/restdocs/request/RequestParametersSnippetTests.java b/spring-restdocs-core/src/test/java/org/springframework/restdocs/request/RequestParametersSnippetTests.java index 20480652..4e533fd9 100644 --- a/spring-restdocs-core/src/test/java/org/springframework/restdocs/request/RequestParametersSnippetTests.java +++ b/spring-restdocs-core/src/test/java/org/springframework/restdocs/request/RequestParametersSnippetTests.java @@ -128,4 +128,16 @@ public class RequestParametersSnippetTests extends AbstractSnippetTests { .build()); } + @Test + public void additionalDescriptors() throws IOException { + this.snippet.expectRequestParameters("additional-descriptors") + .withContents(tableWithHeader("Parameter", "Description").row("a", "one") + .row("b", "two")); + RequestDocumentation.requestParameters(parameterWithName("a").description("one")) + .and(parameterWithName("b").description("two")) + .document(operationBuilder("additional-descriptors") + .request("http://localhost").param("a", "bravo") + .param("b", "bravo").build()); + } + }