How to use Spring REST Docs

This recipe introduces using Spring REST Docs to document RESTful services.

Introduction

By combining hand-written documentation written with AsciiDoctor and auto-generated snippets created by Spring MVC unit tests, Spring REST Docs provides a good and always update-to-date way to document application's RESTful services.

Prerequisite

Java 7 and Spring Framework 4.2 are the minimum requirements.

Configuration

You will need to add the following dependency to the project's pom.xml. 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>1.1.2.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>1.5.3</version>
            <dependencies>
                <dependency>
                    <groupId>org.asciidoctor</groupId>
                        <artifactId>asciidoctorj</artifactId>
                        <version>1.5.4.1</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 test

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. java @Rule public JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation( "target/generated-snippets" ); Then configure MockMvc in a method annotated with @Before method. ```java

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 "Generate document snippets" section to see how the parameterized directory will be interpreted.

Write unit test to invoke the RESTful service and document the API

In the following unit test case, we * perform a HTTP GET against a RESTful service endpoint; * set the values for four path parameters which are accountNumber, lobType, term, sequence, and context; * set the value for a request parameter named asOf; * set the acceptable media type of the HTTP response; * validate the response status code is 200; * validate the response pay load; * explicitly document all path parameters; * explicitly document 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 case of the above example, the documentation snippets will be 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 a index.adoc file under directory src/main/asciidoc/. In this file , you will use 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 at prepare-package phase. In the case of the above example, the index.adoc will be rendered as index.html and stored in 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.

Contactez-nous