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.
The characteristics of microservices were defined by James Lewis and Martin Fowler. We can summarise the technical characteristics as:
In the Spring platform, these characteristics are supported by the following libraries:
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:
Lets divide the process into the following steps:
We’ll build a simple Hello World service which exposes a /greeting
resource with a GET
method 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 full pom.xml file is available here but the main interest is in the configuration for the Swagger Codegen plugin.
<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:
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:
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
in: body
in the API specWe 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.
This provides a home for package level documentation and package level annotations.
package com.example.api.hello.v1.model;
Holds the configurable properties that you want to ship along with the interface.
hello.endpoint: http://localhost:8090/api/v1/hello
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.