Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Spring REST Docs Versus SpringFox Swagger for API Documentation

DZone's Guide to

Spring REST Docs Versus SpringFox Swagger for API Documentation

Want to know more about Spring REST Docs and SpringFox Swagger? Check out this blogger's opinion on when it's best to use these for API documentation.

· Java Zone ·
Free Resource

The CMS developers love. Open Source, API-first and Enterprise-grade. Try BloomReach CMS for free.

Recently, I have come across some articles and mentions about Spring REST Docs, where it has been present as a better alternative to traditional Swagger docs. Until now, I was always using Swagger for building API documentation, so I decided to try Spring REST Docs. You may even read on the main page of that Spring project (https://spring.io/projects/spring-restdocs) some references to Swagger, for example: “This approach frees you from the limitations of the documentation produced by tools like Swagger."  Are you interested in building API documentation using Spring REST Docs? Let’s take a closer look at that project!

The first difference, in comparison to Swagger, is a test-driven approach to generating API documentation. Thanks to that, Spring REST Docs ensure that the documentation is always generated accurately and matches the actual behavior of the API. When using Swagger SpringFox library, you just need to enable it for the project and provide some configuration to force it to work following your expectations. I have already described the usage of Swagger 2 for automated build API documentation for Spring Boot-based applications in my two previous articles:

The articles mentioned above describe, in greater detail, how to use SpringFox Swagger in your Spring Boot application to automatically generate API documentation based on the source code. Here, I’ll give you a short introduction to that technology and how to easily find the differences between usage of Swagger2 and Spring REST Docs.

1. Using Swagger2 With Spring Boot

To enable the SpringFox library for your application, you need to include the following dependencies to pom.xml.

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>2.9.2</version>
</dependency>
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>2.9.2</version>
</dependency>


Then, you should annotate the main or configuration class with @EnableSwagger2. You can also customize the behavior of SpringFox library by declaring the Docket bean.

@Bean
public Docket swaggerEmployeeApi() {
    return new Docket(DocumentationType.SWAGGER_2)
        .select()
            .apis(RequestHandlerSelectors.basePackage("pl.piomin.services.employee.controller"))
            .paths(PathSelectors.any())
        .build()
        .apiInfo(new ApiInfoBuilder().version("1.0").title("Employee API").description("Documentation Employee API v1.0").build());
}


Now, after running the application, the documentation is available under the context path /v2/api-docs. You can also display it in your web browser using the Swagger UI available at site /swagger-ui.html.

spring-cloud-3
It looks easy? Let’s see how to do this with Spring REST Docs.

2. Using Asciidoctor With Spring Boot

There are some other differences between Spring REST Docs and SpringFox Swagger. By default, Spring REST Docs uses Asciidoctor. Asciidoctor processes plain text and produces HTML, styled and laid out to suit your needs. If you prefer, Spring REST Docs can also be configured to use Markdown. This really distinguished it from Swagger, which uses its own notation called OpenAPI Specification.

Spring REST Docs makes use of snippets that are produced by tests written with Spring MVC’s test framework, Spring WebFlux’s WebTestClient or REST Assured 3. I’ll show you an example based on Spring MVC.

I suggest you begin by creating your base Asciidoc file. It should be placed in the src/main/asciidoc directory in your application source code. I don’t know if you are familiar with the Asciidoctor notation, but it is really intuitive. The sample shown below demonstrates two important things. First, we’ll display the version of the project taken from pom.xml. Then, we’ll include the snippets generated during JUnit tests by declaring macro called operation containing document name and list of snippets. We can choose between such snippets like curl-request, http-request, http-response, httpie-request, links, request-body, request-fields, response-body, response-fields or path-parameters. The document name is determined by name of the test method in our JUnit test class.

= RESTful Employee API Specification
{project-version}
:doctype: book

== Add a new person

A `POST` request is used to add a new person

operation::add-person[snippets='http-request,request-fields,http-response']

== Find a person by id

A `GET` request is used to find a new person by id

operation::find-person-by-id[snippets='http-request,path-parameters,http-response,response-fields']


The source code fragment with Asciidoc notation is just a template. We would like to generate an HTML file, which prettily displays all our automatically generated staff. To achieve it we should enable ,the plugin asciidoctor-maven-plugin in the project’s pom.xml. In order to display the Maven project version, we need to pass it to the Asciidoc plugin configuration attributes. We also need to spring-restdocs-asciidoctordependency to that plugin.

<plugin>
    <groupId>org.asciidoctor</groupId>
    <artifactId>asciidoctor-maven-plugin</artifactId>
    <version>1.5.6</version>
    <executions>
        <execution>
            <id>generate-docs</id>
            <phase>prepare-package</phase>
            <goals>
                <goal>process-asciidoc</goal>
            </goals>
            <configuration>
                <backend>html</backend>
                <doctype>book</doctype>
                <attributes>
                    <project-version>${project.version}</project-version>
                </attributes>
            </configuration>
        </execution>
    </executions>
    <dependencies>
        <dependency>
            <groupId>org.springframework.restdocs</groupId>
            <artifactId>spring-restdocs-asciidoctor</artifactId>
            <version>2.0.0.RELEASE</version>
        </dependency>
    </dependencies>
</plugin>


Now, the documentation is automatically generated during Maven to build from our api.adoc file located inside src/main/asciidoc directory. But, we still need to develop the JUnit API tests that automatically generate required snippets. Let’s do that in the next step.

3. Generating Snippets for Spring MVC

First, we should enable Spring REST Docs for our project. To achieve this, we have to include the following dependency.

<dependency>
    <groupId>org.springframework.restdocs</groupId>
    <artifactId>spring-restdocs-mockmvc</artifactId>
    <scope>test</scope>
</dependency>


Now, all we need to do is to implement the JUnit tests. Spring Boot provides an @AutoConfigureRestDocs annotation that allows you to leverage Spring REST Docs in your tests.
In fact, we need to prepare the standard Spring MVC test using MockMvcbean. I also mocked some methods implemented by EmployeeRepository. Then, I used some static methods provided by Spring REST Docs with support for generating documentation of request and response payloads. First of those methods is the document("{method-name}/",...), which is responsible for generating snippets under the directory target/generated-snippets/{method-name}, where the method name is the name of the test method formatted using kebab-case. I have described all the JSON fields in the requests using requestFields(...) and responseFields(...) methods.

@RunWith(SpringRunner.class)
@WebMvcTest(EmployeeController.class)
@AutoConfigureRestDocs
public class EmployeeControllerTest {

    @MockBean
    EmployeeRepository repository;
    @Autowired
    MockMvc mockMvc;

    private ObjectMapper mapper = new ObjectMapper();

    @Before
    public void setUp() {
        Employee e = new Employee(1L, 1L, "John Smith", 33, "Developer");
        e.setId(1L);
        when(repository.add(Mockito.any(Employee.class))).thenReturn(e);
        when(repository.findById(1L)).thenReturn(e);
    }

    @Test
    public void addPerson() throws JsonProcessingException, Exception {
        Employee employee = new Employee(1L, 1L, "John Smith", 33, "Developer");
        mockMvc.perform(post("/").contentType(MediaType.APPLICATION_JSON).content(mapper.writeValueAsString(employee)))
            .andExpect(status().isOk())
            .andDo(document("{method-name}/", requestFields(
                fieldWithPath("id").description("Employee id").ignored(),
                fieldWithPath("organizationId").description("Employee's organization id"),
                fieldWithPath("departmentId").description("Employee's department id"),
                fieldWithPath("name").description("Employee's name"),
                fieldWithPath("age").description("Employee's age"),
                fieldWithPath("position").description("Employee's position inside organization")
            )));
    }

    @Test
    public void findPersonById() throws JsonProcessingException, Exception {
        this.mockMvc.perform(get("/{id}", 1).accept(MediaType.APPLICATION_JSON))
            .andExpect(status().isOk())
            .andDo(document("{method-name}/", responseFields(
                fieldWithPath("id").description("Employee id"),
                fieldWithPath("organizationId").description("Employee's organization id"),
                fieldWithPath("departmentId").description("Employee's department id"),
                fieldWithPath("name").description("Employee's name"),
                fieldWithPath("age").description("Employee's age"),
                fieldWithPath("position").description("Employee's position inside organization")
            ), pathParameters(parameterWithName("id").description("Employee id"))));
    }

}


If you would like to customize some settings of Spring REST Docs, you should provide @TestConfiguration class inside the JUnit test class. In the following code fragment, you may see an example of such customization. I overrode default snippets output directory from index to test method-specific name and forced the generation of sample request and responses using the prettyPrint option (single parameter in the separated line).

@TestConfiguration
static class CustomizationConfiguration implements RestDocsMockMvcConfigurationCustomizer {

    @Override
    public void customize(MockMvcRestDocumentationConfigurer configurer) {
        configurer.operationPreprocessors()
            .withRequestDefaults(prettyPrint())
            .withResponseDefaults(prettyPrint());
    }

    @Bean
    public RestDocumentationResultHandler restDocumentation() {
        return MockMvcRestDocumentation.document("{method-name}");
    }
}


Now, if you execute the mvn clean install on your project, you should see the following structure inside your output directory.
rest-api-docs-3

4. Viewing and Publishing API Docs

Once we have successfully built our project, the documentation has been generated. We can display an HTML file available at target/generated-docs/api.html. It provides the full documentation of our API.

rest-api-docs-1
And, the next part:

rest-api-docs-2
You may also want to publish this inside your application JAR file. If you configure the maven-resources-plugin, the following example is visible and would be available under the /static/docs directory inside JAR.

<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>


Conclusion

That's it for this post! The sample service generating documentation using Spring REST Docs is available on GitHub under repository https://github.com/piomin/sample-spring-microservices-new/tree/rest-api-docs/employee-service. I’m not sure that Swagger and Spring REST Docs should be treated as competitive solutions. I use Swagger for the simple testing of an API on the running application or exposing the specification that can be used for the automated generation of a client code. Spring REST Docs can be used for generating documentation that can be published somewhere and “is accurate, concise, and well-structured. This documentation then allows your users to get the information they need with a minimum of fuss." I think there are no obstacles to using Spring REST Docs and SpringFox Swagger together in your project to provide the most valuable documentation of API exposed in your application.

BloomReach CMS: the API-first CMS of the future. Open-source & enterprise-grade. - As a Java developer, you will feel at home using Maven builds and your favorite IDE (e.g. Eclipse or IntelliJ) and continuous integration server (e.g. Jenkins). Manage your Java objects using Spring Framework, write your templates in JSP or Freemarker. Try for free.

Topics:
java ,swagger 2 ,spring boot ,spring fox swagger ,asciidoctor ,spring mvc ,tutorial ,api docs ,spring rest docs

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}