Spring Boot, Jersey, and Swagger: Always Happy Together
We are on the cusp of the API economy: APIs are everywhere, boosting digital transformation and disrupting the way we think, so a shift is also required in the way we develop.
APIs are expected to enable automation, in turn driving efficiency, consistency, and cost savings. API quality matters, both for API consumers and implementers. For these reasons, building an API infrastructure from scratch may not be a good idea. It is much easier and more productive to use a good framework or library, often more than one.
From a development point of view, it's crucial to achieve the target whilst ensuring the fulfillment of the following requirements: timing, cost saving, and quality. Standardization is an important way to achieve those goals: to ensure consistency, speed up development, enable factorization and simplify maintenance.
Furthermore, a very important factor in APIs is complete and accurate documentation., and best of all, the documentation should be produced and provided in a standard form, to automate the documentation process and to ensure a great overall experience in API consuming.
Even for the simplest API, achieving all these goals and accomplishing all the required tasks may not be so simple for a developer. A minimal infrastructure must be set up, a set of components has to be selected, configured, and enabled to work together. The API implementation stack configuration can be a complex, repetitive, and error-prone process. The developer should not take care about the configuration and components integration details, focusing on the business tasks the API has to face and resolve.
It is where standards, frameworks, and libraries come to help, taking charge of the API infrastructure setup and configuration and leaving the developer free to focus on the API goals. In one sentence: focus on what matters and forget the tedious stuff.
In this post, I would like to show you how the Holon Platform can be used in conjunction with some of the most known and industry-standard libraries to face this challenges.
We'll start from the beginning, showing how to create a simple API service. We'll focus on project setup and configuration, leaving out the API business logic concerns. In fact, this API will only provide a single "ping" operation, which will respond with a pong
message.
The building blocks we're going to use for this project are:
- Spring Boot for auto-configuration and execution using an embedded servlet container.
- Jersey, the reference JAX-RS implementation, to create the API operations using the RESTful paradigm.
- JSON as data interchange format.
- Swagger (OpenAPI) for API documentation.
- Spring Boot Actuator for service monitoring and management.
- The Holon Platform JAX-RS module, to leverage on some configuration facilities and automate the API documentation creation and provisioning.
The code of this example is available on GitHub: https://github.com/holon-platform/spring-boot-jaxrs-swagger-api-example.
Creating the API Application
We'll use Maven for project setup and dependency management, so let's start by configuring the project's pom
dependencies.
First of all, we import the Holon Platform BOM (Bill of Materials); this way we'll no longer need to specify the Holon Platform artifacts version. The right version of each artifact is declared and provided by the platform BOM.
<dependencyManagement>
<dependencies>
<!-- Holon Platform BOM -->
<dependency>
<groupId>com.holon-platform</groupId>
<artifactId>bom</artifactId>
<version>5.0.2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
We'll use the Holon JAX-RS Spring Boot starter with Jersey as implementation, so we declare the following dependency:
<!-- Holon JAX-RS using Jersey -->
<dependency>
<groupId>com.holon-platform.jaxrs</groupId>
<artifactId>holon-starter-jersey</artifactId>
</dependency>
Do you prefer to use Resteasy as JAX-RS implementation? It's only a matter of configuration, just change the Holon starter to use it:
<!-- Holon JAX-RS using Resteasy -->
<dependency>
<groupId>com.holon-platform.jaxrs</groupId>
<artifactId>holon-starter-resteasy</artifactId>
</dependency>
These Holon Spring Boot starters inherit the standard Spring Boot web starters, and provide embedded servlet container configuration, logging, and Holon-specific auto-configuration facilities.
By default, Tomcat is used as the embedded servlet container. Want to use Undertow? Just change the starter name (for example, holon-starter-jersey-undertow
). Concerning JSON data format instead, Jackson is automatically set up. What if Gson is your preferred choice? It's only about changing a name again (for example, holon-starter-jersey-gson
).
Now, independently from the starter you chose, we have to create just two Java classes. The first one, which we'll call Application
, is the Spring Boot application entry-point, which triggers auto-configuration and provides the main method used to run the application itself, starting the embedded servlet container and deploying our API endpoints:
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
An application.yml
file can be used to provide application configuration properties. For example, to configure the embedded server port:
server:
port: 9999
Next, it's time to create the API endpoint, which will provide the API operations listening to the HTTP requests and returning the corresponding responses, using JSON as the data format. As said before, this simple API will only provide a ping operation, mapped to the GET
request method, returning a pong
response encoded as JSON. Finally, we want to map the API operations endpoint to the base "/api" path. Using JAX-RS, this is how the API endpoint can be defined:
@Component
@Path("/api")
public class ApiEndpoint {
@GET
@Path("/ping")
@Produces(MediaType.APPLICATION_JSON)
public Response ping() {
return Response.ok("pong").build();
}
}
Note the @Component
annotation on the API endpoint class. This is a standard Spring annotation to declare this class as a Spring component, candidate for auto-detection. Relying on the Holon Platform auto-configuration features, this class will be automatically detected and registered as a JAX-RS resource in Jersey (or Resteasy). And of course, will be enabled as a Spring component, allowing, for example, dependency injections.
To run the application, we'll use the Spring Boot Maven plugin, declaring it in the project pom
:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution><goals><goal>repackage</goal></goals></execution>
</executions>
</plugin>
</plugins>
</build>
This way, a runnable jar will be created by the Spring Boot plugin, with all the required dependencies and able to execute standalone using a JRE.
To test the application, we can use the run Spring Boot maven goal this way:
mvn spring-boot:run
That's it. The application can be now started, activating our API service. The ping operation will be available sending an HTTP GET request to an URL like this:
http://hostname:9999/api/ping
Obtaining a response like the following:
HTTP/1.1 200
Content-Type: application/json
Content-Length: 4
pong
Documenting the API Operations
We'll use Swagger for API documentation. The Swagger specification is now the foundation of the Open API Initiative, which is trying to standardizing on how REST APIs are described.
The Holon Platform provides many configuration facilities for Swagger, perfectly integrated with JAX-RS and the Spring Boot auto-configuration architecture.
Let's start adding the Holon Platform Swagger dependency to our project pom
:
<dependency>
<groupId>com.holon-platform.jaxrs</groupId>
<artifactId>holon-jaxrs-swagger</artifactId>
</dependency>
From now on, the Holon Platform auto-configuration services will auto-detect any JAX-RS endpoint annotated with the standard Swagger @Api
annotation and automatically create a JAX-RS endpoint to generate and provide the Swagger API documentation. By default, this endpoint will be mapped to the /api-docs
path and supports a type
query parameter to obtain the Swagger API documentation as JSON (the default behaviour) or YAML.
Standard Swagger annotations are supported to enrich and configure the API documentation, such as @ApiOperation
. Additionally, the Holon Platform Swagger module provides the @ApiDefinition
annotation, which can be used to configure the overall API information (such the title and the version) and to change the default API documentation endpoint path. In this example, we want to use the /api/docs
path to provide the API documentation.
So you want to modify the ApiEndpoint
class this way:
@ApiDefinition(docsPath = "/api/docs", title = "Example API", version = "v1", prettyPrint = true)
@Api("Test API")
@Component
@Path("/api")
public class ApiEndpoint {
@ApiOperation("Ping request")
@ApiResponses({ @ApiResponse(code = 200, message = "OK: pong", response = String.class) })
@GET
@Path("/ping")
@Produces(MediaType.APPLICATION_JSON)
public Response ping() {
return Response.ok("pong").build();
}
}
This way, the Swagger API documentation can be obtained in JSON format performing a GET request to the URL:
http://hostname:9999/api/docs
Or in the YAML format:
http://hostname:9999/api/docs?type=yaml
Using the Swagger Editor to display the API documentation, it will appear like this:
Monitoring the API Application
As the last step, we want to add application monitoring and management capabilities, using the Spring Boot Actuator, which adds several production grade services to obtain application information, health check, configuration and so on.
To enable the Spring Boot Actuator endpoints auto-configuration, we have to add the following dependencies to the project pom
:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.11.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
<version>1.5.8.RELEASE</version>
</dependency>
Now a set of monitoring endpoints should be registered. For example, the health check endpoint listens to the /health
path. So we expect to obtain the health information performing a GET
request to an URL like this:
http://localhost:9999/health
But wait... things do not go as we expected: the server responds with a 404
(not found) error code! Why?
This is a well-known and annoying problem which occurs when the Jersey servlet is mapped to the root context path. The problem is that Jersey will get all the request. It does not know that it needs to forward to any actuator endpoints.
This can be resolved by change Jersey to be used as filter instead of a servlet. Using Spring Boot we can do this using a configuration property in the application.yml
file:
spring:
jersey:
type: filter
But this is not enough: we also have to set the Jersey property to forward requests for URLs it doesn't know. With the Holon Platform JAX-RS module, this is simple, just another configuration property to set:
holon:
jersey:
forwardOn404: true
Well done, everything work as expected! The health check endpoint is reachable and provides the following JSON response content:
{"status":"UP"}
Summary
With 2 Java classes, a pom
and a Spring Boot configuration file, we set up a production-grade API application, able to be run standalone, with API documentation and monitoring capabilities. Now it's time to focus on business tasks, making the API somehow useful!
This article is adapted from one originally published in the Holon Platform website: https://holon-platform.com/blog/spring-boot-jersey-and-swagger-always-happy-together/
The source code of the example API created in this post is available on GitHub: https://github.com/holon-platform/spring-boot-jaxrs-swagger-api-example