All posts by christoph

API-first meets Java

Introduction

In this workshop, we’re going to define a REST API and implement it in Java. Furthermore, we’re going to do it using the API-first methodology, which means we’re going to first define the API in a language-independent fashion (using OpenAPI) and then we’re going to implement that API in Java.

Why would we do this? In the API-first methodology, the API exists independently from its implementation. There are a number of good reasons for doing this, the most important one being that the API represents a contract with its clients, which must maintain its integrity over time and therefore must be free of implementation details. In order to avoid getting stuck on a specific technology stack, it must be possible to take an existing API and reimplement it on a different technology stack (e.g. Go, Python, Javascript) without breaking the API contract the clients depend on. Additional benefits include being able to take advantage of documentation and test tools which are available to APIs defined using standards like OpenAPI.

Why use Java? After all, there are a number of other languages which are better suited to implementing REST APIs. The answer is that Java is still the most important language for enterprise development and therefore there are many situations where it makes sense to implement REST services in Java. Luckily, tools like Spring Boot and the OpenAPI/Swagger Java Inflector make it relatively straightforward to use the API-first methodology in Java.

Whats wrong with the “API-second” approach: The traditional approach (let’s call it the API-second approach) is to publish an existing Java service using Jersey or some other REST framework. However, this approach turns out to be a bad idea in practice since it’s almost impossible to avoid Java-specific details leaking into the API and later changes to the implementation may inadvertently break the API.

The technology stack used in this workshop

  • Java
  • Spring Boot (Java application server)
  • Swagger Inflector (to wire the API to Java)
  • Visual Studio Code (Editor/IDE)
  • RestAssured.io (to test the api)

The code for the workshop is available on GitHub at:

https://github.com/armstrongconsulting/code-samples/tree/master/spring-boot-api-first-demo

Step 1: Design a first version of your API.

The online swagger editor is a great tool for defining the API. Point your browser at https://editor.swagger.io, Choose the “File/Import Url” and enter “https://petstore.swagger.io/v2/swagger.json”, since for the purposes of this workshop, we’ll implement the well-known “petstore” API. With the online editor you can very quickly create your own first draft of your API. When you are satisfied, download a YAML version of your API and store it for later use and update.

Step 2: Boot up your framework with Spring Initilizr in Visual Studio Code

Create a new spring-boot project, as described here: https://code.visualstudio.com/docs/java/java-spring-boot. Use the latest spring boot version (we used 2.1.1 when creating this workshop) and add the “Web” and “Jersey (JAX-RS)” dependencies (since swagger inflector is based on jersey).

Add the swagger inflector dependency to the pom.xml.


Note: The 1.xx branch of swagger-inflector is only compatible to Open-Api Version 2, the 2.xx branch is currently under development and will support OAS3 as well.

Step 3: Run an implementation of your API with swagger-inflector, explore it with swagger-ui

In order that swagger inflector can interpret your API, follow these steps:

Copy the downloaded yaml file to src/main/ressources/swagger.yaml

Configure  jersey to load the swagger inflector resource. We have combined all relevant code in one configuration class, which you’ll  find here (SwaggerConfig.java). The “SwaggerConfig.java” additionally configures CORS so that your API can be contacted from anywhere.

Configure some important application.properties wich

  • Boot up the server at port 8080
  • Configure some important Jackson properties so that dates are properly serialised
  • set the jersey application path to /api

Allow your application to serve static content (e.g. the swagger-ui application) by creating a WebConfig.java

The artefacts for swagger-ui are brought in via webjars simply by adding the following to the pom.xml

If you run your application now, swagger ui should boot up under the following url

http://localhost:8080/webjars/swagger-ui/3.20.3/index.html?url=/api/v2/swagger.yaml

(Note: this assumes that the “basePath” in swagger.yaml is set to /v2!)

Step 4: Implement your api

The model

Swagger generator is a great tool to save us from a lot of boilerplate.  Together with maven it will help you build your model. Adding the the swagger-codegen-maven-plugin and the build-helper-maven-plugin to the pom.xml does the magic. For details see the pom.xml on GitHub

The controller

Other swagger frameworks depend on generating the api specification from the implementation, or to generate the implementation from the api specification. Swagger inflector takes an alternative approach and interprets the swagger.yaml file on the fly and routes the request to a controller.

Here is our example of implementing one api method:

The sample implementation simply takes the provided Id, adds a dummy name and returns the “demo pet”. Since swagger inflector is running in “DEVELOPMENT” mode (see SwaggerConfig.java), it automatically provides dummy implementations for all other methods.

Step 5: Test your API

We have chosen rest-assured to test our APIs in unit and integration tests, since it’s simple and intuitive (see pom.xml which shows which artefact will be required in the test scope). The following unit test verifies that our PetController returns a valid result when fetching a pet:

Conclusion

Its perhaps not the easiest way to publish a REST API, but combining Java and the API-first methodology provides the best of both worlds – the correctness of an API defined using the OpenAPI standards and the performance, static typing and enterprise development ecosystem of Java.

Keeping your database schemas in sync with your model

Hibernate’s hbm2ddl.auto setting allows you to create, update, and validate a database schemas based on the mapping configuration. The create & update settings are great in development environments, since they will ensure your database schema will always be in sync with your model. We would not recommend these settings in an production environment because, there we need to have more fine grained control over database updates (hbm2ddl is too “magical” for production). Additionally, there may be updates to the data which cannot be handled by Hibernate’s hbm2ddl.auto implementation (e.g. content-related updates rather than structural).

Some people would say, “such database updates should not be done by the application, but rather by the database administrator”. However, for most applications, you want the code to maintain the database structure – otherwise you have terrible trouble keeping test and staging databases up to date.

To achieve this we “upgrade” our databases with our own implementation, using plain JDBC. A meta table in the schema holds a version number which gets checked during the application’s start up. If the version in the database does not match the code version, the application upgrades the database schema accordingly.

We need to have our own database upgrade execute before Hibernate intercepts. Otherwise Hibernate will complain that tables or columns which should be created by our upgrade procedure are not yet available.

This can be achieved by a bean, which implements the BeanFactoryPostProcessor.

All what’s missing now is the definition of the bean in the applicationContext.xml file.

That’s it. The application context auto-detects BeanFactoryPostProcessor beans in their bean definitions and applys them before any other beans get created. If you are concearned about the order of loading, your bean can implement the “Ordered” interface in addition.

Quartz, Spring & Hibernate/JPA

Establishing a hibernate session in a wicket application is done by means of the OpenSessionInViewFilter class, which binds a Hibernate Session to the thread for the entire processing of the request. You’ll find plenty of references by googling for Wicket and Hibernate.

If you need background jobs to be executed, Quartz is a fantastic library, providing scheduling with cron syntax. Quartz is trivial to integrate into your application (whether with Spring or without), but we had a hard time to figure out how to handle Hibernate sessions correctly. When you want to use one of your DAOs in a Quartz Job you are very likely to hit a “Session is closed!” exception from Hibernate. The reason for this is that the Quartz Job does not run within the context of the servlet, therefore nobody took care of establishing a Hibernate Session.

Below you’ll find a sample Quartz Job which shows how to set up the Hibernate session like OpenSessionInViewFilter does during a servlet request:

Below you’ll find the relevant sections from the corresponding applicationContext.xml file.

Thanks to Uwe Schäfer who helped us find this solution!