Skip to content

Commit 4d37dea

Browse files
committed
Add support for generating snippets in Markdown
This commit introduces support for generating snippets formatted using Markdown. Asciidoctor remains the default. A new SnippetFormat abstraction has been introduced with Asciidoctor and Markdown implementations provided out of the box. Markdown-formatted templates are also provided for all of the default snippets. Please refer to the updated reference documentation for further details. Closes gh-150 Closes gh-19
1 parent b34d2dd commit 4d37dea

File tree

99 files changed

+2089
-1026
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

99 files changed

+2089
-1026
lines changed

config/checkstyle/checkstyle.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@
7373
<module name="AvoidStarImport" />
7474
<module name="AvoidStaticImport">
7575
<property name="excludes"
76-
value="com.jayway.restassured.RestAssured.*, org.junit.Assert.*, org.junit.Assume.*, org.hamcrest.CoreMatchers.*, org.hamcrest.Matchers.*, org.mockito.Mockito.*, org.mockito.BDDMockito.*, org.mockito.Matchers.*, org.springframework.restdocs.curl.CurlDocumentation.*, org.springframework.restdocs.headers.HeaderDocumentation.*, org.springframework.restdocs.hypermedia.HypermediaDocumentation.*, org.springframework.restdocs.mockmvc.IterableEnumeration.*, org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.*, org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.*, org.springframework.restdocs.payload.PayloadDocumentation.*, org.springframework.restdocs.operation.preprocess.Preprocessors.*, org.springframework.restdocs.request.RequestDocumentation.*, org.springframework.restdocs.restassured.RestAssuredRestDocumentation.*, org.springframework.restdocs.restassured.operation.preprocess.RestAssuredPreprocessors.*, org.springframework.restdocs.snippet.Attributes.*, org.springframework.restdocs.test.SnippetMatchers.*, org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*, org.springframework.test.web.servlet.result.MockMvcResultMatchers.*" />
76+
value="com.jayway.restassured.RestAssured.*, org.junit.Assert.*, org.junit.Assume.*, org.hamcrest.CoreMatchers.*, org.hamcrest.Matchers.*, org.mockito.Mockito.*, org.mockito.BDDMockito.*, org.mockito.Matchers.*, org.springframework.restdocs.curl.CurlDocumentation.*, org.springframework.restdocs.headers.HeaderDocumentation.*, org.springframework.restdocs.hypermedia.HypermediaDocumentation.*, org.springframework.restdocs.mockmvc.IterableEnumeration.*, org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.*, org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.*, org.springframework.restdocs.payload.PayloadDocumentation.*, org.springframework.restdocs.operation.preprocess.Preprocessors.*, org.springframework.restdocs.request.RequestDocumentation.*, org.springframework.restdocs.restassured.RestAssuredRestDocumentation.*, org.springframework.restdocs.restassured.operation.preprocess.RestAssuredPreprocessors.*, org.springframework.restdocs.snippet.Attributes.*, org.springframework.restdocs.snippet.SnippetFormats.*, org.springframework.restdocs.test.SnippetMatchers.*, org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*, org.springframework.test.web.servlet.result.MockMvcResultMatchers.*" />
7777
</module>
7878
<module name="IllegalImport" />
7979
<module name="RedundantImport" />

docs/src/docs/asciidoc/configuration.adoc

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,7 @@ TIP: To configure a request's context path, use the `contextPath` method on
4242
[[configuration-snippet-encoding]]
4343
=== Snippet encoding
4444

45-
The default encoding used by Asciidoctor is `UTF-8`. Spring REST Docs adopts the same
46-
default for the snippets that it generates. You can change the default snippet encoding
45+
The default snippet encoding is `UTF-8`. You can change the default snippet encoding
4746
using the `RestDocumentationConfigurer` API. For example, to use `ISO-8859-1`:
4847

4948
[source,java,indent=0,role="primary"]
@@ -60,6 +59,26 @@ include::{examples-dir}/com/example/restassured/CustomEncoding.java[tags=custom-
6059

6160

6261

62+
[[configuration-snippet-format]]
63+
=== Snippet format
64+
65+
The default snippet format is Asciidoctor. Markdown is also supported out of the box. You
66+
can change the default format using the `RestDocumentationConfigurer` API:
67+
68+
[source,java,indent=0,role="primary"]
69+
.MockMvc
70+
----
71+
include::{examples-dir}/com/example/mockmvc/CustomFormat.java[tags=custom-format]
72+
----
73+
74+
[source,java,indent=0,role="secondary"]
75+
.REST Assured
76+
----
77+
include::{examples-dir}/com/example/restassured/CustomFormat.java[tags=custom-format]
78+
----
79+
80+
81+
6382
[[configuration-default-snippets]]
6483
=== Default snippets
6584

docs/src/docs/asciidoc/index.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,5 @@ include::documenting-your-api.adoc[]
2626
include::customizing-requests-and-responses.adoc[]
2727
include::configuration.adoc[]
2828
include::working-with-asciidoctor.adoc[]
29+
include::working-with-markdown.adoc[]
2930
include::contributing.adoc[]

docs/src/docs/asciidoc/introduction.adoc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ services that is accurate and readable.
66

77
Writing high-quality documentation is difficult. One way to ease that difficulty is to use
88
tools that are well-suited to the job. To this end, Spring REST Docs uses
9-
http://asciidoctor.org[Asciidoctor]. Asciidoctor processes plain text and produces
10-
HTML, styled and layed out to suit your needs.
9+
http://asciidoctor.org[Asciidoctor] by default. Asciidoctor processes plain text and
10+
produces HTML, styled and layed out to suit your needs. If you prefer, Spring REST Docs
11+
can also be configured to use Markdown.
1112

1213
Spring REST Docs makes use of snippets produced by tests written with
1314
{spring-framework-docs}/#spring-mvc-test-framework[Spring MVC Test] or
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
[[working-with-markdown]]
2+
== Working with Markdown
3+
4+
This section describes any aspects of working with Markdown that are particularly
5+
relevant to Spring REST Docs.
6+
7+
8+
9+
[[working-with-markdown-limitations]]
10+
=== Limitations
11+
12+
Markdown was originally designed for people writing for the web and, as such, isn't
13+
as well-suited to writing documentation as Asciidoctor. Typically, these limitations
14+
are overcome by using another tool that builds on top of Markdown.
15+
16+
Markdown has no official support for tables. Spring REST Docs' default Markdown snippet
17+
templates use https://michelf.ca/projects/php-markdown/extra/#table[Markdown Extra's table
18+
format].
19+
20+
21+
22+
[[working-with-markdown-including-snippets]]
23+
=== Including snippets
24+
25+
Markdown has no built-in support for including one Markdown file in another. To include
26+
the generated snippets of Markdown in your documentation, you should use an additional
27+
tool that supports this functionality. One example that's particularly well-suited to
28+
documenting APIs is https://github.com/tripit/slate[Slate].
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
* Copyright 2014-2016 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.example.mockmvc;
18+
19+
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration;
20+
21+
import org.junit.Before;
22+
import org.junit.Rule;
23+
import org.springframework.beans.factory.annotation.Autowired;
24+
import org.springframework.restdocs.RestDocumentation;
25+
import org.springframework.restdocs.snippet.SnippetFormats;
26+
import org.springframework.test.web.servlet.MockMvc;
27+
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
28+
import org.springframework.web.context.WebApplicationContext;
29+
30+
public class CustomFormat {
31+
32+
@Rule
33+
public final RestDocumentation restDocumentation = new RestDocumentation("build");
34+
35+
@Autowired
36+
private WebApplicationContext context;
37+
38+
private MockMvc mockMvc;
39+
40+
@Before
41+
public void setUp() {
42+
// tag::custom-format[]
43+
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
44+
.apply(documentationConfiguration(this.restDocumentation)
45+
.snippets().withFormat(SnippetFormats.markdown()))
46+
.build();
47+
// end::custom-format[]
48+
}
49+
50+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright 2014-2016 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.example.restassured;
18+
19+
import org.junit.Before;
20+
import org.junit.Rule;
21+
import org.springframework.restdocs.RestDocumentation;
22+
import org.springframework.restdocs.snippet.SnippetFormats;
23+
24+
import com.jayway.restassured.builder.RequestSpecBuilder;
25+
import com.jayway.restassured.specification.RequestSpecification;
26+
27+
import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.documentationConfiguration;
28+
29+
public class CustomFormat {
30+
31+
@Rule
32+
public final RestDocumentation restDocumentation = new RestDocumentation("build");
33+
34+
private RequestSpecification spec;
35+
36+
@Before
37+
public void setUp() {
38+
// tag::custom-format[]
39+
this.spec = new RequestSpecBuilder()
40+
.addFilter(documentationConfiguration(this.restDocumentation)
41+
.snippets().withFormat(SnippetFormats.markdown()))
42+
.build();
43+
// end::custom-format[]
44+
}
45+
46+
}

spring-restdocs-core/src/main/java/org/springframework/restdocs/config/RestDocumentationConfigurer.java

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,13 +93,20 @@ protected final AbstractConfigurer getTemplateEngineConfigurer() {
9393

9494
private static final class TemplateEngineConfigurer extends AbstractConfigurer {
9595

96-
private TemplateEngine templateEngine = new MustacheTemplateEngine(
97-
new StandardTemplateResourceResolver());
96+
private TemplateEngine templateEngine;
9897

9998
@Override
10099
public void apply(Map<String, Object> configuration,
101100
RestDocumentationContext context) {
102-
configuration.put(TemplateEngine.class.getName(), this.templateEngine);
101+
TemplateEngine engineToUse = this.templateEngine;
102+
if (engineToUse == null) {
103+
SnippetConfiguration snippetConfiguration = (SnippetConfiguration) configuration
104+
.get(SnippetConfiguration.class.getName());
105+
engineToUse = new MustacheTemplateEngine(
106+
new StandardTemplateResourceResolver(
107+
snippetConfiguration.getFormat()));
108+
}
109+
configuration.put(TemplateEngine.class.getName(), engineToUse);
103110
}
104111

105112
private void setTemplateEngine(TemplateEngine templateEngine) {
@@ -117,8 +124,12 @@ public void apply(Map<String, Object> configuration,
117124
RestDocumentationContext context) {
118125
WriterResolver resolverToUse = this.writerResolver;
119126
if (resolverToUse == null) {
127+
SnippetConfiguration snippetConfiguration = (SnippetConfiguration) configuration
128+
.get(SnippetConfiguration.class.getName());
120129
resolverToUse = new StandardWriterResolver(
121-
new RestDocumentationContextPlaceholderResolver(context));
130+
new RestDocumentationContextPlaceholderResolver(context),
131+
snippetConfiguration.getEncoding(),
132+
snippetConfiguration.getFormat());
122133
}
123134
configuration.put(WriterResolver.class.getName(), resolverToUse);
124135
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Copyright 2014-2016 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.restdocs.config;
18+
19+
import org.springframework.restdocs.snippet.SnippetFormat;
20+
21+
/**
22+
* An encapsulation of the configuration for documentation snippets.
23+
*
24+
* @author Andy Wilkinson
25+
*/
26+
class SnippetConfiguration {
27+
28+
private final String encoding;
29+
30+
private final SnippetFormat format;
31+
32+
SnippetConfiguration(String encoding, SnippetFormat format) {
33+
this.encoding = encoding;
34+
this.format = format;
35+
}
36+
37+
String getEncoding() {
38+
return this.encoding;
39+
}
40+
41+
SnippetFormat getFormat() {
42+
return this.format;
43+
}
44+
45+
}

spring-restdocs-core/src/main/java/org/springframework/restdocs/config/SnippetConfigurer.java

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@
2424
import org.springframework.restdocs.curl.CurlDocumentation;
2525
import org.springframework.restdocs.http.HttpDocumentation;
2626
import org.springframework.restdocs.snippet.Snippet;
27-
import org.springframework.restdocs.snippet.WriterResolver;
27+
import org.springframework.restdocs.snippet.SnippetFormat;
28+
import org.springframework.restdocs.snippet.SnippetFormats;
2829

2930
/**
3031
* A configurer that can be used to configure the generated documentation snippets.
@@ -51,8 +52,18 @@ public abstract class SnippetConfigurer<P, T> extends AbstractNestedConfigurer<P
5152
*/
5253
public static final String DEFAULT_SNIPPET_ENCODING = "UTF-8";
5354

55+
/**
56+
* The default format for documentation snippets.
57+
*
58+
* @see #withFormat(SnippetFormat)
59+
*/
60+
public static final SnippetFormat DEFAULT_SNIPPET_FORMAT = SnippetFormats
61+
.asciidoctor();
62+
5463
private String snippetEncoding = DEFAULT_SNIPPET_ENCODING;
5564

65+
private SnippetFormat snippetFormat = DEFAULT_SNIPPET_FORMAT;
66+
5667
/**
5768
* Creates a new {@code SnippetConfigurer} with the given {@code parent}.
5869
*
@@ -64,8 +75,8 @@ protected SnippetConfigurer(P parent) {
6475

6576
@Override
6677
public void apply(Map<String, Object> configuration, RestDocumentationContext context) {
67-
((WriterResolver) configuration.get(WriterResolver.class.getName()))
68-
.setEncoding(this.snippetEncoding);
78+
configuration.put(SnippetConfiguration.class.getName(), new SnippetConfiguration(
79+
this.snippetEncoding, this.snippetFormat));
6980
configuration.put(ATTRIBUTE_DEFAULT_SNIPPETS, this.defaultSnippets);
7081
}
7182

@@ -93,4 +104,17 @@ public T withDefaults(Snippet... defaultSnippets) {
93104
this.defaultSnippets = Arrays.asList(defaultSnippets);
94105
return (T) this;
95106
}
107+
108+
/**
109+
* Configures the format of the documentation snippets.
110+
*
111+
* @param format the snippet format
112+
* @return {@code this}
113+
*/
114+
@SuppressWarnings("unchecked")
115+
public T withFormat(SnippetFormat format) {
116+
this.snippetFormat = format;
117+
return (T) this;
118+
}
119+
96120
}

0 commit comments

Comments
 (0)