Platform Engineering

Bharat Patel

Microservices using Spring Boot & Swagger - Part 1

Posted by Bharat Patel on 10 August 2018

Microservices, tech, api, java, swagger, spring

Microservices have become popular as a way of eliminating hidden dependencies between software components and allowing fine-grained deployment without dragging along unneccessary context. In this way, microservices promote autonomy for agile development teams and allow an application to evolve more naturally and in some cases to develop faster.

I like Java, so I’m going to show you one process and framework to develop microservices for the JVM. This is the first part of a series of articles which walks through an end-to-end service development. This first article (Part 1) goes through some of the foundational aspects before we get into more specific details in future articles. Part 2 will cover code generation from the Swagger spec before later articles dive into implementing some of the features of well-behaved services.

Microservices Characteristics

The characteristics of microservices were defined by James Lewis and Martin Fowler. We can summarise the technical characteristics as:

  • A single runtime executable—eliminating runtime library dependencies and dependence on runtime container packaging.
  • A well-defined API which supports a single useful business function.
  • Standard interfaces for health-monitoring and logging which facilitate management of a large number of independent services

In the Spring platform, these characteristics are supported by the following libraries:

  • The single executable characteristic is afforded by Spring Boot which gives each microservice its own HTTP stack (unfortunately at some cost to memory footprint) and allows each service to be deployed and managed independently.
  • Business function is supported by “contract first” development using Swagger (see the next section for more on this).
  • Health monitoring is supported by Spring Actuator
  • Standardised logging is supported by Sleuth

Contract First Development

A microservice should provide a single useful business function. There are nuances here which boil down to a microservice representing a business level of abstraction in its API representation. A microservice should abstract the consumer of the service from underlying technical details such as data schemas or implementation specifics. Abstraction allows the service implementation to evolve with minimal disruption to consumers.

A common anti-pattern in API design is to start with the implementation and then generate an API specification — the “click-first” approach. The resulting interfaces tend to be overly technical, “developer hostile” and tightly coupled to implementation details.

A better pattern is to design the service API first in collaboration with consumers and other stakeholders. The API specification can then be shared among different development teams tasked with service implementation, consumer implementation, testing etc.

For this service, we will use Swagger to design a REST-ish API but the principle and technique is independent of whether we are REST-ish or not. For example, an RPC style service could easily be designed using protocol buffers or other interface specification tools.

We’ve found it beneficial to manage the API specification in its own git repository, separate from the service implementation. The benefits include:

  • Easy to accommodate changes post review as we only have an API spec.
  • Service implementors and consumers can start their development work in parallel thereby increasing team autonomy and reducing cross-team dependencies.
  • Provides ability to the service consumers to test against service mocks.

Lets divide the process into the following steps:

  • Setup a service interface project.
  • Define the service specification in a Swagger file and generate code stubs.
  • Setup a service implementation project that uses the generated code stubs.

Service Interface

We’ll build a simple Hello World service which exposes a /greeting resource with a GETmethod which responds with a JSON payload containing “Hello World” message string when invoked.

Start by creating a Hello World Interface project called api-helloworld-v1-interface. The structure of the project conforms to a standard maven project structure.

The pom.xml file contains dependencies for the following libraries:

  • The Swagger Codegen Maven plugin for building the server stubs from the Swagger specification
  • Apache CXF dependency for pulling out the CXF modules that implement the JAX-RS specification
  • Jackson JSON Provider dependency for JSON marshalling and unmarshalling used the the JAX-RS. The provider gets auto registered with JAX-RS
  • Spring Boot dependency and
  • PojoBuilder to build supporting POJOs for JSON serialisation.

The full pom.xml file is available here but the main interest is in the configuration for the Swagger Codegen plugin.

pom.xml

<plugins>
    <plugin>
      <groupId>io.swagger</groupId>
      <artifactId>swagger-codegen-maven-plugin</artifactId>
      <version>2.2.2</version>
      <executions>
        <execution>
          <id>generate-client-jar</id>
          <phase>generate-sources</phase>
          <goals>
            <goal>generate</goal>
          </goals>
          <configuration>
            <inputSpec>src/main/resources/swagger.yml</inputSpec>
            <templateDirectory>src/main/resources/swagger-codegen-templates/jaxrs-cxf</templateDirectory>
            <language>jaxrs-cxf</language>
            <configOptions>
              <sourceFolder>src/gen/java</sourceFolder>
              <apiPackage>${swagger-gen.api.package}</apiPackage>
              <modelPackage>${swagger-gen.model.package}</modelPackage>
              <serializableModel>true</serializableModel>
              <useJaxbAnnotations>false</useJaxbAnnotations>
              <dateLibrary>java8</dateLibrary>
            </configOptions>
          </configuration>
        </execution>
        <execution>
          <id>generate-html</id>
          <phase>generate-sources</phase>
          <goals>
            <goal>generate</goal>
          </goals>
          <configuration>
            <inputSpec>src/main/resources/swagger.yml</inputSpec>
            <language>html</language>
          </configuration>
        </execution>
      </executions>
    </plugin>
  </plugins>

Our Swagger Codegen plugin is configured for two execution tasks:

  • generation of code stubs including server-side code, client-side code and model POJOs,
  • generation of HTML documentation.

For the code generation, we provide the input specification as being in the file src/main/resources/swagger.yml. Code generation templates are provided in the folder src/main/resources/swagger-codegen-templates/jaxrs-cxf. These templates use Mustache syntax to generate the following code stubs:

  • API: This template is used by the code gen plugin to defines the Java interface. The generated Java interface contains one method per operationId defined in the swagger spec annotated with corresponding HTTP method, request/response media type ,query parameters, header parameters, body parameters and form parameters. The tags:field of the swagger spec forms the part of the Java interface name suffixed by Api
  • API implementation: as specified in the apiImpl.mustache file, this template generates the stubbed implementation of the API.
  • Model POJOs: which generates a POJO for each object specified in the Swagger spec
  • Body Parameters: Adds the input arguments to the generated API methods which are defined as in: body in the API spec

We have used the code generation language as jaxrs-cxf as CXF provides a standard way to build RESTFul services via Annotations using HTTP binding.

HTML generation is fairly straightforward, simply specifying the input spec as our swagger.yml file and HTML as the output language.

package-info.java

This provides a home for package level documentation and package level annotations.

package com.example.api.hello.v1.model;

hello-client.yml

Holds the configurable properties that you want to ship along with the interface.

hello.endpoint: http://localhost:8090/api/v1/hello

Next Steps

This post has discussed some of the rationale around the tools we can use to develop microservices in Java and Spring. We’ve reviewed the project setup and structure for the service interface. In the next part of this series, we’ll discuss the Swagger API definition and look at the source code generation process.

 

If you like what you read, join our team as we seek to solve wicked problems within Complex Programs, Process Engineering, Integration, Cloud Platforms, DevOps & more!

 

GET IN TOUCH!

Leave a comment on this blog: