Using Spring REST Docs
Spring REST Docs provides a useful and always update-to-date way to document an application’s RESTful services by combining hand-written documentation created with Asciidoctor and auto-generated snippets created by Spring MVC unit tests.
The @AutoConfigureRestDocs
annotation in Spring Boot allows you to leverage Spring REST Docs in your tests. This guide explains how to configure Spring REST Docs and use it in combination with JUnit for unit testing.
Configuration steps for Spring REST Docs
Java 7 and Spring Framework 4.2 are the minimum requirements, and you will need to add the following dependency to your project’s pom.xml
file. You can omit the version if it is already managed by the parent POM.
<dependency>
<groupId>org.springframework.restdocs</groupId>
<artifactId>spring-restdocs-mockmvc</artifactId>
<version>2.0.5.RELEASE</version>
<scope>test</scope>
</dependency>
The following two plugins are configured to process Asciidoctor files and include the documentation during application packaging.
<build>
<plugins>
<plugin>
<groupId>org.asciidoctor</groupId>
<artifactId>asciidoctor-maven-plugin</artifactId>
<version>2.1.0</version>
<dependencies>
<dependency>
<groupId>org.asciidoctor</groupId>
<artifactId>asciidoctorj</artifactId>
<version>2.4.2</version>
</dependency>
</dependencies>
<executions>
<execution>
<id>generate-docs</id>
<phase>prepare-package</phase>
<goals>
<goal>process-asciidoc</goal>
</goals>
<configuration>
<backend>html</backend>
<doctype>book</doctype>
<attributes>
<snippets>${project.build.directory}/generated-snippets</snippets>
</attributes>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<executions>
<execution>
<id>copy-resources</id>
<phase>prepare-package</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${project.build.outputDirectory}/static/docs</outputDirectory>
<resources>
<resource>
<directory>${project.build.directory}/generated-docs</directory>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
Set up for JUnit testing
First declare a JUnit
rule which is configured with the output directory where the generated document snippets will be saved. This output directory should match the snippets directory specified in the pom.xml
file.
@Rule
public JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation( "target/generated-snippets" );
Then configure MockMvc in a method annotated with @Before method.
private MockMvc mockMvc;
@Before
public void setUp() {
this.mockMvc = MockMvcBuilders
.webAppContextSetup( this.context )
.apply( documentationConfiguration( this.restDocumentation ) )
.alwaysDo(
document(
"{method-name}/{step}",
preprocessRequest(prettyPrint()),
preprocessResponse(prettyPrint())
)
)
.build();
}
In the above set up, parameterized output directory is set to be {method-name}/{step}
, where:
{method-name}
is the name of the test method, formatted using kebab-case{step}
represents the count of calls made to the service in the current test
Refer to the section Generate document snippets to see how the parameterized directory is interpreted.
Write unit test to invoke the RESTful service and document the API
The following unit test case does the following actions:
- Performs an
HTTP GET
against a RESTful service endpoint - Sets the values for four path parameters which are
accountNumber, lobType, term, sequence, and context
- Sets the value for a request parameter named
asOf
- Sets the acceptable media type of the HTTP response
- Validates the response status code is 200
- Validates the response payload
- Explicitly documents all path parameters
- Explicitly documents the request parameter
Other HTTP request components such as HTTP request headers can also be set and documented. Other HTTP response components such as HTTP response headers can be documented as well.
@Test
public void testEventSyncFoundEventsWithAsOf() throws Exception {
String url: "/sync/{accountNumber}/{lobType}/{term}/{sequence}/{context}";
EventsDetails eventDetails = mockEventDetailsAsOf();
given( eventService.readEvents( any( ReadEvents.class ) ) ).willReturn( eventDetails);
this.mockMvc.perform(
RestDocumentationRequestBuilders
.get( url, accountNumber, lobType, term, sequence, "PriorCarrier" )
.param("asOf", String.valueOf( Clock.systemUTC().millis() ))
.accept(MediaType.APPLICATION_JSON)
)
.andExpect( status().isOk() )
.andExpect( content().json( mapper.writeValueAsString( eventDetails.getEvents()) ) )
.andDo(
document("{method-name}/{step}",
pathParameters (
parameterWithName( "accountNumber" ).description( "The account number of" ),
parameterWithName( "lobType" ).description( "The line of business" ),
parameterWithName( "term" ).description( "The term" ),
parameterWithName( "sequence" ).description( "The sequence" ),
parameterWithName( "context" ).description( "The context of" )
),
requestParameters(
parameterWithName( "asOf" ).description( "The asOf" )
)
)
);
verify (eventService, times(1)).readEvents(any (ReadEvents.class));
}
Generate document snippets
When the unit test is executed, the documentation snippets are generated. In the above example, the documentation snippets are generated in the directory target/generated-snippets/test-event-sync-found-events-with-as-of/1
and the snippets include the following Asciidoctor documentation:
curl-request.adoc
http-request.adoc
http-response.adoc
path-parameters.adoc
request-parameters.adoc
Integrate and use the generated Asciidoctor snippets
Create an index.adoc
file under directory src/main/asciidoc/
. In this file, you will use the Asciidoctor “include” macro to include the above generated Asciidoctor snippets, as shown below.
To sync up with asOf time, you will:
include::{snippets}/test-event-sync-found-events-with-as-of/1/curl-request.adoc[]
The HTTP request sent to the server is:
include::{snippets}/test-event-sync-found-events-with-as-of/1/http-request.adoc[]
The path parameters are:
include::{snippets}/test-event-sync-found-events-with-as-of/1/path-parameters.adoc[]
The request parameters are:
include::{snippets}/test-event-sync-found-events-with-as-of/1/request-parameters.adoc[]
The HTTP response is:
include::{snippets}/test-event-sync-found-events-with-as-of/1/http-response.adoc[]
As specified in the pom.xml
, the asciidoctor-maven-plugin
will execute the “process-asciidoc” goal during the prepare-package
phase. In the above example, the index.adoc
will be rendered as index.html
and stored in the directory target/generated-docs
. Then the maven-resources-plugin
executes the “copy-resources” goal to copy the rendered index.html
to the right directory for application packaging.
Keep Learning
Spring offers a useful getting started guide on Spring Rest Docs with a tutorial that walks you through the process of using them.