Many developers including myself doesn’t give the importance needed to create documentation for our code. The problem is once an intial documentation is created, we developers need to keep it up to date. There is more work especially if your code or api is contantly changing. And I have some great news on this problem. To help us lazy developers, we have open source that can up date documentation when our code changes. There are many tools that helps documenting our softwares such as swagger-ui, ascii-doctor, javadoc etc. In this post lets see about how to create an up-to-date documentation for an api developed with spring-boot using ascii-dcotor.

Pre-requisites

Let’s assume that you have a spring boot application with some REST api. For this post, I am going to take a POST api that will create a new customer.

@PostMapping("customer")
public ResponseEntity newCustomer(@RequestBody @Valid CreateCustomerRequest customerDto) {
  Customer customerModel = Customer.builder()
    .firstName(customerDto.getFirstName())
    .lastName(customerDto.getLastName())
    .username(customerDto.getUsername())
    .build();
  customerRepository.save(customerModel);
  return new ResponseEntity(HttpStatus.CREATED);
}

Setup in brief

There is a [spring-restdocs-mockmvc](https://mvnrepository.com/artifact/org.springframework.restdocs/spring-restdocs-mockmvc) dependency that generates the curl or http requests and the corresponding response based on your test cases. So whenever your code changes, all that you need to do is update your test cases to reflect the change. Then ascii-doctor has the maven plugin that can be used to generate documentation files in pdf/html formats. Finally we will host the docs within the spring-boot application itself.

Create WebMvc test case

First lets create a simple WebMvcTest for the create customer api.

@Test
public void shouldReturnDefaultMessage() throws Exception {
    CreateCustomerRequest request = CreateCustomerRequest.builder().age(50).firstName("abc").lastName("xyz")
        .username("abc").build();
    this.mockMvc.perform(MockMvcRequestBuilders.post("/customer")
        .accept(MediaType.APPLICATION_JSON_VALUE)
        .contentType(MediaType.APPLICATION_JSON_VALUE)
        .content(new ObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(request)))
        .andExpect(MockMvcResultMatchers.status().isCreated())
        .andDo(MockMvcRestDocumentation.document("create-customer"));
}

If you notice the last line of the test case above, I call MockMvcRestDocumentation.document function. This function captures the curl, http request/response for the above test case and creates it in the target/snippets directory. Now run the test case. Note that as of now the code will give compile error as we are yet to add the dependencies in the following steps.

Add dependency spring-restdocs-mockmvc

As mentioned in the setup, then we need to add the spring-restdocs-mockmvc dependency

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

The dependency version is derived from spring boot parent dependencies. So the version need not be explictly specified. Note that since I use mockmvc, I use the spring-restdocs-mockmvc dependency. Same way you can use spring-restdocs-restassured or spring-restdocs-webtestclient if you use RestTemplate or WebTestClient in the test case.

Root documentation file

Now let’s, add another adoc file called index.adoc that will include the curl command and http request body/response generated by spring-restdocs-mockmvc. The index.adoc file looks like this and be placed in the src/main/docs folder.

= Documentation for creating a new customer

This is an example for creating a new customer:

.request
include::{snippets}/create-customer/http-request.adoc[]

.Sample curl request
include::{snippets}/create-customer/curl-request.adoc[]

.response
include::{snippets}/create-customer/http-response.adoc[]

As you see we are including the http=request, curl-request, http-response adoc files generated in the snippets directory. We will specify the directory for snippets in the asccidoctor plugin that we are adding next.

Add the asciidoctor-maven-plugin

The asciidoctor-maven-plugin converts asciidoc to html/pdf documents using asciidoctor. Add the asciidoctor-maven-plugin in pom.xml and configure it as follows:

<plugin>
   <groupId>org.asciidoctor</groupId>
   <artifactId>asciidoctor-maven-plugin</artifactId>
   <version>2.1.0</version>
   <executions>
      <execution>
         <id>generate-docs</id>
         <phase>prepare-package</phase>
         <goals>
            <goal>process-asciidoc</goal>
         </goals>
         <configuration>
            <sourceDocumentName>index.adoc</sourceDocumentName>
            <backend>html</backend>
            <attributes>
               <snippets>${project.build.directory}/snippets</snippets>
            </attributes>
            <sourceDirectory>src/main/doc</sourceDirectory>
            <outputDirectory>${project.build.outputDirectory}/static/docs</outputDirectory>
         </configuration>
      </execution>
   </executions>
</plugin>

If you see the plugin configuration we see the backend option specifies the documentation be generated in html format. The snippets attribute mentions the snippets be placed in the ${project.build.directory}/snippets i.e target/snippets directory. Also, we mention that the source asciidoc files are in src/main/doc directory and the output files be placed in ${project.build.outputDirectory}/static/docs i.e target/generated-classes/static/docs directory. Hence the sourceDocumentName option specifies the base document index.adoc, which means the file is present in src/main/docs directory.

Run the test case

All is set, let’s run the test case now.

mvn clean install

Once it is complete you will see the snippets are in target/snippets/create-customer directory. The curl request adoc snippet looks like this,

[source,bash]
----
$ curl 'http://localhost:8080/customer' -i -X POST \
    -H 'Content-Type: application/json;charset=UTF-8' \
    -H 'Accept: application/json' \
    -d '{
  "firstName" : "abc",
  "lastName" : "xyz",
  "age" : 50,
  "username" : "abc"
}'
 ----

There are additional files as well as mentioned here. The spring-restdocs-mockmvc dependency has generated the curl sample and the request/response body used by the test case.

Also note that there is a doc folder in the target/generated-classes/static directory. This is created by the asciidoctor plugin and has our documentation in html fomat in file index.html.

Now go to http://localhost:8080/docs/index.html and you will see the documentation generated like this

sample-documentation

References:

Comments