Getting Started With Spring REST Docs
After we have finished this webinar, we:
- Can create a Maven project that generates our API documentation.
- Know what Spring REST Docs is.
- Can configure Spring REST Docs when we are using Spring Boot.
- Understand how we can document our REST API with Spring REST Docs and Asciidoctor.
This webinar assumes that:
Get the source code from Github
The text version of this webinar is given in the following:
A Quick Introduction to Spring REST Docs
Spring REST Docs is a library that allows us document a REST API by writing tests for it. Spring REST Docs uses Asciidoctor by default, but it is possible to use Markdown as well.
When we want to document a REST API with Spring REST Docs, we have to follow these steps:
- We have to generate the snippets which document the behavior of our REST API. To be more specific, these snippets describe both the HTTP requests consumed by our API resources and the HTTP responses returned by our API resources. We can generate these snippets by using either the Spring MVC Test framework, the WebTestClient of Spring WebFlux, or REST Assured 3.
- We have to write the Asciidoctor document which specifies the structure of our API documentation. When we want to document our API resources, we can take advantage of the snippets generated by Spring REST Docs.
We are now familiar with Spring REST Docs. Next, we will find out how we can get the required dependencies with Maven.
Getting the Required Dependencies With Maven
Because we want to integrate Spring REST Docs with Spring MVC Test framework, we have to declare the spring-restdocs-mockmvc dependency in our POM file. Because we are using Spring Boot, we can do this by adding the following snippet to the dependencies section of our POM file:
1<dependency>
2 <groupId>org.springframework.restdocs</groupId>
3 <artifactId>spring-restdocs-mockmvc</artifactId>
4 <scope>test</scope>
5</dependency>
spring-restdocs-mockmvc dependency as well.
Our next step is to configure the Asciidoctor Maven plugin. Let’s find out how we can do it.
Configuring the Asciidoctor Maven Plugin
We use the Asciidoctor Maven plugin for generating the API documentation of our REST API. We can configure this plugin by following these steps:
- Add the
asciidoctor-maven-pluginto our Maven build. - Create an execution that generates our API document when the
prepare-packagephase of the Maven default lifecycle is invoked. Remember to ensure that this execution creates an HTML document and uses the doctype:book. - Add the
spring-restdocs-asciidoctormodule as a dependency of the Asciidoctor Maven plugin. Remember to use the same version that is used by Spring Boot.
We can configure the Asciidoctor Maven plugin by adding the following snippet to the plugins section of our POM file:
1<plugin>
2 <groupId>org.asciidoctor</groupId>
3 <artifactId>asciidoctor-maven-plugin</artifactId>
4 <version>1.5.6</version>
5 <executions>
6 <execution>
7 <id>generate-docs</id>
8 <phase>prepare-package</phase>
9 <goals>
10 <goal>process-asciidoc</goal>
11 </goals>
12 <configuration>
13 <backend>html</backend>
14 <doctype>book</doctype>
15 </configuration>
16 </execution>
17 </executions>
18 <dependencies>
19 <dependency>
20 <groupId>org.springframework.restdocs</groupId>
21 <artifactId>spring-restdocs-asciidoctor</artifactId>
22 <version>${spring-restdocs.version}</version>
23 </dependency>
24 </dependencies>
25</plugin>
Additional Reading:
Before we will find out how we can use Spring REST Docs with Spring MVC Test framework, we will take a quick look at the system under test.
Introduction to System Under Test
During this webinar we will write unit and integration tests for a simple controller method which processes GET requests send to the path: ‘/api/hello’. This method simply returns the string: ‘Hello World!’ in the response body.
The source code of the HelloWorldController class looks as follows:
1import org.springframework.web.bind.annotation.RequestMapping;
2import org.springframework.web.bind.annotation.RequestMethod;
3import org.springframework.web.bind.annotation.RestController;
4
5@RestController
6@RequestMapping("/api/hello")
7class HelloWorldController {
8
9 @RequestMapping(method = RequestMethod.GET)
10 String sayHello() {
11 return "Hello World!";
12 }
13}
Let’s move on and find out how we can use Spring REST Docs when we are writing unit tests for this controller.
Writing Unit Tests
Before we can configure Spring REST Docs, we have to create a new test class and ensure that its test methods are run when we run our unit tests. The source code of our test class looks as follows:
1import org.junit.jupiter.api.Tag;
2
3@Tag(TestTags.UNIT_TEST)
4class HelloWorldControllerTest {
5}
When we are writing unit tests for a Spring MVC controller, we want to configure the system under test by using the standalone configuration. That’s why we have to integrate Spring REST Docs with Spring MVC Test framework by following these steps:
- Integrate Spring REST Docs with JUnit 5. We can do this using the
RestDocumentationExtensionclass. - Add a
MockMvcfield to our test class. - Create a setup method that is run before a test method is run. Because we are using the
RestDocumentationExtension, our setup method will take aRestDocumentationExtensionobject as a method parameter. - Implement the setup method by creating a new
MockMvcobject. Remember to integrate Spring REST Docs with Spring MVC Test framework.
After we have integrated Spring REST Docs with Spring MVC Test framework, the source code of our test class looks as follows:
1import org.junit.jupiter.api.BeforeEach;
2import org.junit.jupiter.api.Tag;
3import org.junit.jupiter.api.extension.ExtendWith;
4import org.springframework.restdocs.RestDocumentationExtension;
5import org.springframework.test.web.servlet.MockMvc;
6import org.springframework.test.web.servlet.setup.MockMvcBuilders;
7
8import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration;
9
10@ExtendWith(RestDocumentationExtension.class)
11@Tag(TestTags.UNIT_TEST)
12class HelloWorldControllerTest {
13
14 private MockMvc mockMvc;
15
16 @BeforeEach
17 void configureSystemUnderTest(RestDocumentationExtension restDocumentation) {
18 this.mockMvc = MockMvcBuilders.standaloneSetup(new HelloWorldController())
19 .apply(documentationConfiguration(restDocumentation))
20 .build();
21 }
22}
We can finally create the Asciidoctor snippets which describe the details of the consumed HTTP request and the returned HTTP response. We can create these snippets by following these steps:
- Create a nested test class which contains our test methods.
- Add a new test method to the nested test class.
- Send an HTTP request to the tested controller method.
- Ensure that Spring REST Docs generates the snippets which document the behavior of our API resource. We can do this by invoking the
static document()method of theMockMvcRestDocumentationclass. When we invoke this method, we have to provide the identifier of the documented API resource as a method parameter.
After we have written the test method which documents the behavior of our API resource, the source code of our test class looks as follows:
1import org.junit.jupiter.api.*;
2import org.junit.jupiter.api.extension.ExtendWith;
3import org.springframework.restdocs.RestDocumentationExtension;
4import org.springframework.test.web.servlet.MockMvc;
5import org.springframework.test.web.servlet.setup.MockMvcBuilders;
6
7import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
8import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration;
9import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
10
11@ExtendWith(RestDocumentationExtension.class)
12@Tag(TestTags.UNIT_TEST)
13class HelloWorldControllerTest {
14
15 private MockMvc mockMvc;
16
17 @BeforeEach
18 void configureSystemUnderTest(RestDocumentationExtension restDocumentation) {
19 this.mockMvc = MockMvcBuilders.standaloneSetup(new HelloWorldController())
20 .apply(documentationConfiguration(restDocumentation))
21 .build();
22 }
23
24 @Nested
25 @DisplayName("Say Hello")
26 class SayHello {
27
28 @Test
29 @DisplayName("Create the Spring REST Docs snippets")
30 void createSpringRESTDocsSnippets() throws Exception {
31 mockMvc.perform(get("/api/hello"))
32 .andDo(document("say-hello"));
33 }
34 }
35}
There are two things I want to point out:
- By default, Spring REST Docs generates the Asciidoc snippets to the target/generated-snippets directory. The snippets which describe the behavior of one API resource, are generated to the target/generated-snippets/[resource idenfier] directory. The resource identifier is a unique string which is given to the
document()method of theMockMvcRestDocumentationclass as a method parameter. - Our test class has naturally other unit tests as well. I won’t write these tests during this webinar because they are not relevant for the topic of this webinar. However, it’s important to understand that we should always write a separate test method which documents the tested API resource. This is a good idea because it ensures that every test method has only one responsibility.
Additional Reading:
We can generate the Asciidoctor snippets which document the tested API resource when we are writing unit tests. Let’s move on and find out how we can generate these snippets when we are writing integration tests.
Writing Integration Tests
Again, before we can configure Spring REST Docs, we have to create a new test class and ensure that its test methods are run when we run our integration tests. The source code of our test class looks as follows:
1import org.junit.jupiter.api.Tag;
2
3@Tag(TestTags.INTEGRATION_TEST)
4class SayHelloTest {
5
6}
When we are writing integration tests for a Spring MVC controller, we want to configure the system under test by using the web application context based configuration. That’s why we have to integrate Spring REST Docs with Spring MVC Test framework by following these steps:
- Integrate Spring TestContext framework with JUnit 5.
- Configure the loaded Spring Boot application class.
- Ensure that Spring REST Docs is auto-configured by Spring Boot.
- Ensure that Spring Boot creates and configures a new
MockMvcobject. - Add a
MockMvcfield to our test class and ensure that theMockMvcbean is injected into this field by the Spring container.
After we have integrated Spring REST Docs with Spring MVC Test framework, the source code of our test class looks as follows:
1import org.junit.jupiter.api.Tag;
2import org.junit.jupiter.api.extension.ExtendWith;
3import org.springframework.beans.factory.annotation.Autowired;
4import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs;
5import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
6import org.springframework.boot.test.context.SpringBootTest;
7import org.springframework.test.context.junit.jupiter.SpringExtension;
8import org.springframework.test.web.servlet.MockMvc;
9
10@ExtendWith(SpringExtension.class)
11@SpringBootTest(classes = ExampleApplication.class)
12@AutoConfigureMockMvc
13@AutoConfigureRestDocs
14@Tag(TestTags.INTEGRATION_TEST)
15class SayHelloTest {
16
17 @Autowired
18 private MockMvc mockMvc;
19
20}
We can now create the Asciidoctor snippets which describe the details of the consumed HTTP request and the returned HTTP response. We can create these snippets by following these steps:
- Add a new test method to our test class.
- Send an HTTP request to the tested controller method.
- Generate the snippets which document the behavior of the tested API resource.
After we have written the test method which documents the behavior of our API resource, the source code of our test class looks as follows:
1import org.junit.jupiter.api.DisplayName;
2import org.junit.jupiter.api.Tag;
3import org.junit.jupiter.api.Test;
4import org.junit.jupiter.api.extension.ExtendWith;
5import org.springframework.beans.factory.annotation.Autowired;
6import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs;
7import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
8import org.springframework.boot.test.context.SpringBootTest;
9import org.springframework.test.context.junit.jupiter.SpringExtension;
10import org.springframework.test.web.servlet.MockMvc;
11
12import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
13import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
14
15@ExtendWith(SpringExtension.class)
16@SpringBootTest(classes = ExampleApplication.class)
17@AutoConfigureMockMvc
18@AutoConfigureRestDocs
19@Tag(TestTags.INTEGRATION_TEST)
20class SayHelloTest {
21
22 @Autowired
23 private MockMvc mockMvc;
24
25 @Test
26 @DisplayName("Create the Spring REST Docs snippets")
27 void createSpringRESTDocsSnippets() throws Exception {
28 mockMvc.perform(get("/api/hello"))
29 .andDo(document("say-hello"));
30 }
31}
Additional Reading:
We can generate the Asciidoctor snippets which document the tested API resource when we are writing unit and integration tests. Next, we will find out how we can write our API documentation by using Asciidoctor.
Writing Our API Documentation
As we remember, when we write API documentation by using Spring REST Docs, we have to create an Asciidoctor document and include the generated Asciidoctor snippets into that document. If we are using the default configuration of the Asciidoctor Maven plugin, we have to create our Asciidoc document to the src/main/asciidoc directory.
Let’s create a simple Asciidoctor document which has one section called: ‘Resources’. This section will contain the documentation of our API resources.
After we have created this document, its content looks as follows:
1= Hello World Example
2Petri Kainulainen;
3:doctype: book
4:icons: font
5:source-highlighter: highlightjs
6:toc: left
7:toclevels: 4
8:sectlinks:
9
10[[resources]]
11= Resources
Our next step is to document our API resources. We can do this by following these steps:
- Add a subsection called: ‘Say Hello’ to the ‘Resources’ section.
- Describe the HTTP request that is used to obtain a message from our API resource.
- Describe the content of the returned HTTP response.
After we have documented our API resource, the content of our Asciidoctor file looks as follows:
1= Hello World Example
2Petri Kainulainen;
3:doctype: book
4:icons: font
5:source-highlighter: highlightjs
6:toc: left
7:toclevels: 4
8:sectlinks:
9
10[[resources]]
11= Resources
12
13[[resources-say-hello]]
14== Say Hello
15
16We can obtain a message from our REST API by sending a `GET` request to
17the path: `/api/hello`. The following example demonstrates how we can send
18this HTTP request by using curl:
19
20include::{snippets}/say-hello/curl-request.adoc[]
21
22When we send this `GET` request, our REST API returns the HTTP status 200 and
23the message: 'Hello World!' back to us. The following snippet descibes the
24content of the returned HTTP response:
25
26include::{snippets}/say-hello/http-response.adoc[]
snippets attribute contains the root directory in which the snippets are generated.
We have now created a simple API documentation. Let’s move on and find out how we can generate our API documentation with Maven.
Generating Our API Documentation
We can generate our API documentation by running one of the following commands:
1mvn clean package -P dev
2mvn clean package -P integration-test
When we run one of these commands at command prompt, the Asciidoctor Maven plugin creates the API documentation to the target/generated-docs directory.
Let’s summarize what we learned from this webinar.
Summary
This webinar has taught us seven things:
- Spring REST Docs can generate snippets which document the behavior of the tested API resource.
- We can generate these snippets by using either the Spring MVC Test framework, the WebTestClient of Spring WebFlux, or REST Assured 3.
- Before we can use Spring REST Docs, we have to declare the
spring-restdocs-mockmvcdependency in our build script. - We can generate our API documentation by using the Asciidoctor Maven plugin.
- When we want document our REST API by writing unit tests, we have to integrate Spring REST Docs with JUnit 5 by using a custom JUnit 5 extension called
RestDocumentationExtensionclass, and integrate Spring REST Docs with Spring MVC Test framework by using theMockMvcRestDocumentationConfigurerclass. - When we want to document our REST API by writing integration tests, we can integrate Spring REST Docs with Spring MVC Test framework by using the auto-configuration support provided by Spring Boot.
- We can generate the snippets which document the behavior of a tested API resource by invoking the
document()method of theMockMvcRestDocumentationclass.