Add support for using REST Assured to generate documentation snippets

This commit adds a new module, spring-restdocs-restassured, that
can be used to generate documentation snippets when testing a service
with REST Assured.

Please refer to the updated reference documentation for details.

Thanks to Johan Haleby for making a change to REST Assured so that
path parameters could be documented.

Closes gh-102
This commit is contained in:
Andy Wilkinson
2015-09-07 14:36:42 +01:00
parent f73108ae36
commit 130b411e2a
66 changed files with 3361 additions and 433 deletions

View File

@@ -0,0 +1,40 @@
/*
* 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.config;
import java.util.Map;
import org.springframework.restdocs.RestDocumentationContext;
/**
* Abstract configurer that declares methods that are internal to the documentation
* configuration implementation.
*
* @author Andy Wilkinson
*/
public abstract class AbstractConfigurer {
/**
* Applies the configurer to the given {@code configuration}.
*
* @param configuration the configuration to be configured
* @param context the current documentation context
*/
public abstract void apply(Map<String, Object> configuration,
RestDocumentationContext context);
}

View File

@@ -0,0 +1,43 @@
/*
* 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.config;
/**
* Base class for {@link NestedConfigurer} implementations.
*
* @param <P> The type of the configurer's parent
* @author Andy Wilkinson
*/
public abstract class AbstractNestedConfigurer<P> extends AbstractConfigurer implements
NestedConfigurer<P> {
private final P parent;
/**
* Creates a new {@code AbstractNestedConfigurer} with the given {@code parent}.
* @param parent the parent
*/
protected AbstractNestedConfigurer(P parent) {
this.parent = parent;
}
@Override
public final P and() {
return this.parent;
}
}

View File

@@ -0,0 +1,33 @@
/*
* 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.config;
/**
* A configurer that is nested and, therefore, has a parent.
*
* @param <P> The parent's type
* @author Andy Wilkinson
*/
interface NestedConfigurer<P> {
/**
* Returns the configurer's parent.
*
* @return the parent
*/
P and();
}

View File

@@ -0,0 +1,132 @@
/*
* 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.config;
import java.util.Map;
import org.springframework.restdocs.RestDocumentationContext;
import org.springframework.restdocs.snippet.RestDocumentationContextPlaceholderResolver;
import org.springframework.restdocs.snippet.StandardWriterResolver;
import org.springframework.restdocs.snippet.WriterResolver;
import org.springframework.restdocs.templates.StandardTemplateResourceResolver;
import org.springframework.restdocs.templates.TemplateEngine;
import org.springframework.restdocs.templates.mustache.MustacheTemplateEngine;
/**
* Abstract base class for the configuration of Spring REST Docs.
*
* @param <S> The concrete type of the {@link SnippetConfigurer}.
* @param <T> The concrete type of this configurer, to be returned from methods that
* support chaining
* @author Andy Wilkinson
*/
public abstract class RestDocumentationConfigurer<S, T> {
private final WriterResolverConfigurer writerResolverConfigurer = new WriterResolverConfigurer();
private final TemplateEngineConfigurer templateEngineConfigurer = new TemplateEngineConfigurer();
/**
* Returns a {@link SnippetConfigurer} that can be used to configure the snippets that
* will be generated.
*
* @return the snippet configurer
*/
public abstract S snippets();
/**
* Configures the {@link TemplateEngine} that will be used for snippet rendering.
*
* @param templateEngine the template engine to use
* @return {@code this}
*/
@SuppressWarnings("unchecked")
public final T templateEngine(TemplateEngine templateEngine) {
this.templateEngineConfigurer.setTemplateEngine(templateEngine);
return (T) this;
}
/**
* Configures the {@link WriterResolver} that will be used to resolve a writer for a
* snippet.
*
* @param writerResolver The writer resolver to use
* @return {@code this}
*/
@SuppressWarnings("unchecked")
public final T writerResolver(WriterResolver writerResolver) {
this.writerResolverConfigurer.setWriterResolver(writerResolver);
return (T) this;
}
/**
* Returns the configurer used to configure the context with a {@link WriterResolver}.
*
* @return the configurer
*/
protected final AbstractConfigurer getWriterResolverConfigurer() {
return this.writerResolverConfigurer;
}
/**
* Returns the configurer used to configure the context with a {@link TemplateEngine}.
*
* @return the configurer
*/
protected final AbstractConfigurer getTemplateEngineConfigurer() {
return this.templateEngineConfigurer;
}
private static final class TemplateEngineConfigurer extends AbstractConfigurer {
private TemplateEngine templateEngine = new MustacheTemplateEngine(
new StandardTemplateResourceResolver());
@Override
public void apply(Map<String, Object> configuration,
RestDocumentationContext context) {
configuration.put(TemplateEngine.class.getName(), this.templateEngine);
}
private void setTemplateEngine(TemplateEngine templateEngine) {
this.templateEngine = templateEngine;
}
}
private static final class WriterResolverConfigurer extends AbstractConfigurer {
private WriterResolver writerResolver;
@Override
public void apply(Map<String, Object> configuration,
RestDocumentationContext context) {
WriterResolver resolverToUse = this.writerResolver;
if (resolverToUse == null) {
resolverToUse = new StandardWriterResolver(
new RestDocumentationContextPlaceholderResolver(context));
}
configuration.put(WriterResolver.class.getName(), resolverToUse);
}
private void setWriterResolver(WriterResolver writerResolver) {
this.writerResolver = writerResolver;
}
}
}

View File

@@ -0,0 +1,96 @@
/*
* 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.config;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.springframework.restdocs.RestDocumentationContext;
import org.springframework.restdocs.curl.CurlDocumentation;
import org.springframework.restdocs.http.HttpDocumentation;
import org.springframework.restdocs.snippet.Snippet;
import org.springframework.restdocs.snippet.WriterResolver;
/**
* A configurer that can be used to configure the generated documentation snippets.
*
* @param <P> The type of the configurer's parent
* @param <T> The concrete type of the configurer to be returned from chained methods
* @author Andy Wilkinson
*/
public abstract class SnippetConfigurer<P, T> extends AbstractNestedConfigurer<P> {
/**
* The name of the attribute that is used to hold the default snippets.
*/
public static final String ATTRIBUTE_DEFAULT_SNIPPETS = "org.springframework.restdocs.defaultSnippets";
private List<Snippet> defaultSnippets = Arrays.asList(
CurlDocumentation.curlRequest(), HttpDocumentation.httpRequest(),
HttpDocumentation.httpResponse());
/**
* The default encoding for documentation snippets.
*
* @see #withEncoding(String)
*/
public static final String DEFAULT_SNIPPET_ENCODING = "UTF-8";
private String snippetEncoding = DEFAULT_SNIPPET_ENCODING;
/**
* Creates a new {@code SnippetConfigurer} with the given {@code parent}.
*
* @param parent the parent
*/
protected SnippetConfigurer(P parent) {
super(parent);
}
@Override
public void apply(Map<String, Object> configuration, RestDocumentationContext context) {
((WriterResolver) configuration.get(WriterResolver.class.getName()))
.setEncoding(this.snippetEncoding);
configuration.put(ATTRIBUTE_DEFAULT_SNIPPETS, this.defaultSnippets);
}
/**
* Configures any documentation snippets to be written using the given
* {@code encoding}. The default is UTF-8.
*
* @param encoding the encoding
* @return {@code this}
*/
@SuppressWarnings("unchecked")
public T withEncoding(String encoding) {
this.snippetEncoding = encoding;
return (T) this;
}
/**
* Configures the documentation snippets that will be produced by default.
*
* @param defaultSnippets the default snippets
* @return {@code this}
*/
@SuppressWarnings("unchecked")
public T withDefaults(Snippet... defaultSnippets) {
this.defaultSnippets = Arrays.asList(defaultSnippets);
return (T) this;
}
}

View File

@@ -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.
@@ -92,8 +92,9 @@ public class PathParametersSnippet extends AbstractParametersSnippet {
private String extractUrlTemplate(Operation operation) {
String urlTemplate = (String) operation.getAttributes().get(
"org.springframework.restdocs.urlTemplate");
Assert.notNull(urlTemplate,
"urlTemplate not found. Did you use RestDocumentationRequestBuilders to "
Assert.notNull(
urlTemplate,
"urlTemplate not found. If you are using MockMvc, did you use RestDocumentationRequestBuilders to "
+ "build the request?");
return urlTemplate;
}