Java Microservices with MicroProfile – API Documentation

By: Hemankita Perabathini

Eclipse MicroProfile includes support for easily creating documentation of your microservice APIs

APIs are the “glue” that tie microservices together, and cloud-native microservices apps have lots of APIs. Microservices architecture assumes independently-developed services that publish their capabilities via APIs (specifically REST APIs). These APIs represent the public face of the service and should include documentation of their use. APIs also represent the point where scaling and monitoring occurs. Fortunately for Java developers, the Eclipse MicroProfile specification includes the support for easily creating documentation of your APIs.

MicroProfile

If you have created API documentation before, you’re probably familiar with Swagger, RAML, or other such REST API document generators. Swagger is one of the most popular among them in the past few years; the Open API specification is a format that describes the REST APIs and is formerly known as the Swagger Specification. For RESTful web services, the OpenAPI v3 specification is the current contract.

In our last post, we covered how to make microservices resilient using MicroProfile Fault Tolerance. In this installment, I will cover the MicroProfile OpenAPI specification. You can learn how our team implemented it in our simple storefront application (GitHub).

Note: For those who may have joined late, this blog series is based on my team’s experience migrating our simple storefront application from Spring Boot-based microservices to MicroProfile, an optimized enterprise Java programming model for a microservices architecture.  Both the projects are hosted on GitHub. You can access the Spring Boot version of our reference application here and MicroProfile version of our reference application here.

The next two sections compare how the two implementations, Spring Boot and MicroProfile, handle API documentation generation.

Spring Boot – How to generate microservices API doc

Spring REST Docs is used to generate the API documentation for RESTful services. These documents are well-structured, nicely organized, and readable. Spring generates API document test snippets automatically; custom documentation can also be defined. Below are the steps for generating some sample API documentation in Spring Boot.

First, to use the Spring REST docs, define the necessary Maven dependencies for the build as shown below:

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

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

The next step will be to define the REST services. The snippet is an example REST service:

@RestController
public class CatalogController {    
  @RequestMapping("/")
  public @ResponseBody String index() {
    return "Greetings from Catalog Service !";
  }
}

Since the docs are produced from the tests, you must define all the necessary test classes, consistent with the principles of Test-Driven Development. The documentation is generated from the tests and this helps to assure that the documentation accurately reflects the implementation. This example is using JUnit4, and the configuration for its tests are as follows:

@Rule
public JUnitRestDocumentation restDocumentation = 
    new JUnitRestDocumentation("target/generated-snippets");

The annotations below generate the test templates for the simple REST service defined in the earlier step:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = CatalogController.class)
@WebAppConfiguration
public class CatalogControllerTest {
	
  private MockMvc mockMvc;
	
  @Autowired
  private WebApplicationContext context;
	
  @Rule
  public JUnitRestDocumentation restDocumentation = 
    new JUnitRestDocumentation("target/generated-snippets");
	
  @Before
  public void setUp() {
    mockMvc = MockMvcBuilders.webAppContextSetup(context)
      .apply(documentationConfiguration(restDocumentation))
      .build();
  }

  @Test
  public void shouldReturnDefaultMessage() throws Exception {
    mockMvc.perform(RestDocumentationRequestBuilders.get("/")
      .accept(MediaType.APPLICATION_JSON))
      .andExpect(MockMvcResultMatchers.status().isOk())
      .andDo(MockMvcRestDocumentation.document("shouldReturnDefaultMessage"));
  }

}

For this sample, the REST docs test snippets generated will be as follows:

curl-request.adoc

Using these snippets, you can generate the document using AsciiDoc. The Mavin plug-in below handles this:

<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>
        <sourceDocumentName>sample.adoc</sourceDocumentName>
        <backend>html</backend>
        <attributes>
          <snippets>${project.build.directory}/generated-snippets</snippets>
        </attributes>
      </configuration>
    </execution>
  </executions>
</plugin>

The AsciiDoc we used in our sample is as follows:

= How can it be done in Spring Boot?

This is an example for the API documentation generated using Spring REST docs

== Curl Structure
include::{snippets}/shouldReturnDefaultMessage/curl-request.adoc[]

== Request structure
include::{snippets}/shouldReturnDefaultMessage/http-request.adoc[]

== Response structure
include::{snippets}/shouldReturnDefaultMessage/http-response.adoc[]

== HTTPIE Structure
include::{snippets}/shouldReturnDefaultMessage/httpie-request.adoc[]

== Request Body Structure
include::{snippets}/shouldReturnDefaultMessage/request-body.adoc[]

== Response Body Structure
include::{snippets}/shouldReturnDefaultMessage/response-body.adoc[]

Once you run your application, REST docs gives a you nice readable documentation in the form of an HTML file. For our simple sample, it is as follows:

How can it be done in Spring Boot?

Generating documentation from tests is awesome, but currently, Spring REST Docs doesn’t generate OpenAPI docs directly. I would like to see this feature in a future version so that it could generate Spring REST docs and OpenAPI spec files.

MicroProfile – How to generate microservices API doc

MicroProfile OpenAPI includes the API documentation for the RESTful services. It allows the developers to produce OpenAPI v3 documents for their JAX-RS applications, consistent with the OpenAPI Specification. These documents are well-structured, nicely organized, and readable. Underlying docs help a third party developer or user to better understand the existing APIs in the application. The API docs are accessible from the microservices app URL at the /openapi path.

All the JAX-RS annotations can be processed using OpenAPI to produce auto-generated API docs. In our sample application, we used the annotation-based approach. Some of the annotations we used were as follows:

  • @OpenAPIDefinition

  • @Info

  • @Contact

  • @License

  • @APIResponses

  • @APIResponse

  • @Content

  • @Schema

  • @Operation

  • @Parameter

Other ways that OpenAPI can produce API docs include static OpenAPI files, API interfaces, and filter. The annotation-based approach helps us to avoid rewriting the OpenAPI document portions, which are already provided by the JAX-RS framework. Also, all of the annotations are derived from the popular Swagger library so it is very easy for developers already familiar with Swagger to adopt.

Let’s look at the Catalog service in our reference implementation to get an idea of how the OpenAPI implementation uses annotations. Of course, if you prefer to keep this documentation separate from your code, you can also generate the OpenAPI documents using its programming model to provide an OpenAPI model tree or static OpenAPI document or filter. See Documenting RESTful APIs (openliberty.io) for more details.

We chose to add annotations directly to the code because we prefer everything in one place. Below is an excerpt of the annotations for our Catalog service:

@RequestScoped
@Path("/items")
@Produces(MediaType.APPLICATION_JSON)
@OpenAPIDefinition(
  info = @Info(
    title = "Catalog Service",
    version = "0.0",
    description = "Catalog APIs",
    contact = @Contact(
      url = "https://github.com/ibm-cloud-architecture",
      name = "IBM CASE"),
    license = @License(
      name = "License", 
      url = "https://github.com/ibm-cloud-architecture/.../LICENSE")
    )
)

public class CatalogService {
  @GET
  @APIResponses(value = {
    @APIResponse(
      responseCode = "404",
      description = "Items Not Found",
      content = @Content(mediaType = "text/plain")
    ),
    @APIResponse(
      responseCode = "500",
      description = "Internal Server Error",
      content = @Content(mediaType = "text/plain")
    ),
    @APIResponse(
      responseCode = "200",
      description = "List of items from the catalog",
      content = @Content(
        mediaType = "application/json",
        schema = @Schema(implementation = Item.class)
      )
    )
  }
  )
  @Operation(
    summary = "Get Inventory Items",
    description = "Retrieving all the available items from the cache"
  )

  public List getInventory() {
    // Return all items in Inventory
  }
}

For this sample, the OpenAPI UI is shown below:

Open Liberty

The Open API UI generated from the MicroProfile OpenAPI specification is very similar to the one that is generated by the Swagger UI. With this interface, you can easily explore all the available REST APIs in the service.

The API UI returns the document title, description, and various details, like what server the application is running, licenses, model, etc. You can also access individual APIs and try them out. For example, when you click on GET for the sample’s /rest/items, it retrieves the items in the inventory, verifying your understanding of the API:

Open Liberty

This can also help third-party developers understand your APIs better. I think the steps for generating the documentation with the MicroProfile spec were much easier than for Spring Boot.

Conclusion

As previously stated, APIs are the “glue” that tie microservices together. For cloud-native applications, APIs are essential for enabling developers within the organization to enhance them further. To benefit from reuse and consistency of microservice APIs, developers outside the organization will need proper documentation to use your APIs correctly. With annotations defined in the MicroProfile OpenAPI specification, you can easily generate clear documentation for your application.

Conclusion

During my work on this piece, I found the Open Liberty guide Documenting RESTful APIshelpful.

This blog demonstrates how we implemented the API documentation in our sample application using MicroProfile OpenAPI. In our next blog post, we’ll explain how you can monitor your microservices with the MicroProfile Health & Metrics.

Note: See our project ibm-cloud-architecture/refarch-cloudnative-kubernetes on GitHub for more examples. The microservices in our simple storefront application can be run individually using Maven, if you want to run them locally. Of course, you can also run them on IBM Cloud and IBM Cloud Private.

Be the first to hear about news, product updates, and innovation from IBM Cloud