REST APIs are ubiquitous in today's world, ranging from payments, to communication, to banking. Developers can plug-in virtually any specialist service they require for their applications.
So, it comes as no surprise that we at PALO IT are frequently developing APIs for our customers and integrating external APIs with our backend applications. Both our own APIs and external ones can become rather large and extensive, making it time consuming to write them all by hand. Luckily, there are some nifty techniques to make our lives as developers easier and avoid writing repetitive code.
Enter OpenApi 3 specs and code generation!
Imagine someone needs to access our freshly developed API. In the past, we would share our endpoint definitions using a non-standardised way, such as Excel sheets. The consumers of our API would have to implement a client within their application. With large APIs, this can take quite a while. To avoid re-inventing the wheel, the open API spec was created. It enables us to define our REST API contract in a standardised format and easily share it with others.
Thus, an ecosystem of editors and code generation tools were created around the open API specification (of which the latest version is 3.1 at the time of writing). These tools allow us to create API documentation and generate both clients and servers for a vast multitude of programming languages and frameworks. This article will focus on utilising code generation with the popular Java Spring Boot framework which is used in more than a few of our projects.
Definitions
Before we jump into the code, we need to establish some definitions...
Open API specification
The OpenAPI Specification (OAS) defines a standard, language-agnostic interface to RESTful APIs which allows both humans and computers to discover and understand the capabilities of the service without access to source code, documentation, or through network traffic inspection. When properly defined, a consumer can understand and interact with the remote service with a minimal amount of implementation logic.
Client code
Client code is any client SDK that enables us to call a remote REST API. In the context of Spring Boot, client code is usually written using HTTP clients such as the Rest Template or the more recently introduced Webclient.
Server code
Server code refers to any code necessary to create a REST API server. Using Spring Boot, this is usually accomplished with the servlet-api based Spring Web or the newer, non-blocking Spring Webflux.
Code generation
The code generation we will learn about in this tutorial will be done using the OpenAPI Generator. It is a community project widely used by many well-known companies and can generate client code or server stubs from an open API spec in a multitude of programming languages and frameworks. There are many ways to use the generator. It comes as a maven plugin, npm module and standalone JAR. In the following sections we will utilise the maven plugin for convenience, since the Spring Boot project uses it as the build management tool.
On a side note, the OpenAPI Generator was forked from the Swagger Codegen to simplify the original and enable stronger community ownership.
Tutorial Scope
With this tutorial, we will demonstrate how to generate both server-side and client-side code from an Openapi 3 specification. The v3 specification is the latest Openapi iteration and extends the older v2 version with numerous new functionalities and improvements.
For simplicity's sake, the Swagger Petstore will be used for the generation. It is a simple example REST API demonstrating the capabilities of the Open API specification including authorisation, HTTP schemes and API descriptions.
Server
For the server-side, the generator will output traditional Spring Web based code.
Client
To illustrate the client code generation, the reactive WebClient will be used. For our projects, we at PALO IT prefer to use the Webclient because it simplifies performing concurrent calls compared to the Rest Template. Also, the RestTemplate is no longer in active development and remains in maintenance mode. Thus, the WebClient should be preferred for new projects.
Prerequisites
Before getting started, we need to ensure all necessary tools to run the application are available. The tools and installation instruction are below.
Project structure
To become familiar with the components and structure of the project, the main areas of interest are depicted below.
The Petstore Openapi specification in YAML format is kept in the src/main/resources/openapi
folder. Both server and client contain the same spec but have been kept in separate folders for simplicity.
- The generated WebClient code
- Common configuration for the WebClient, SpringDoc API documentation and Jackson parser
- The generated Spring Web server stubs
- Adjustment for the generation templates. Sometimes custom adjustments are needed for the generation process if the default templates are not sufficient. More about this in custom generator templates
- Tests for both generated server and client
The configuration for the OpenAPI Generator can be found in the pom file. To separate configuration for the client- and server generator, maven profiles have been used as seen below.
Spring Web server generator configuration
WebClient generator configuration
Getting Started
Clone the Git repository.
Import the maven project inside the spring-boot-openapi-codegen
using your favorite IDE.
Generate client
Navigate to the project using a terminal and execute the following command to generate the client code.
The generated code can be found in the target
directory.
- Contains the generated APIs
- Shared classes related to authorization
- Generated models
- Re-usable shared support classes
After the generation is complete, the API and model packages (1. and 3.) are copied to com.paloit.clientpetstore.webclient
. The support and authorisation classes are copied as well and contained in the apiclient
and auth
packages.
Client initialization & usage
The client has to be defined as a spring bean. This is done within the com.paloit.config.ApiClientConfig
class. A simple example is depicted below and should be self-explanatory.
After defining the PetApi
as a Spring Bean, it can be auto-wired and used to call the external API as illustrated below.
Custom generator templates
The OpenAPI Generator uses mustache templates to generate client implementations or server stubs. For the majority of cases, these are sufficient to be used out of the box. For custom use cases, they can be adjusted to generate the desired code.
The templates for all programming languages supported by the generator can be found in their git repository.
The templates can be overridden with the OpenAPI Generator maven configuration using the templateDirectory
tag. If a template with the same file name as the original is found in the specified directory, it will override the default template.
The overridden templates for the WebClient were copied to the local /src/main/resources/generator-template-overrides/webclient
directory from the openapi-generator/src/main/resources/Java/libraries/webclient folder in the OpenAPI Generator Git repository.
In this example, the generator templates are used to change a modifier with the generated client to access the ResponseSpec and enable us to have fine-grained handling of HTTP errors. By default, the PetApi client method addPet
only returns a Mono as seen below and the addPetRequestCreation
method is private.
The api.mustache
template is changed at line 72 so the addPetRequestCreation
method becomes public and accessible. The relevant change is depicted below in bold.
Generate server
The server is generated in a similar fashion and illustrates the API first development approach. The open API spec is created first and a server stub is generated from it. The development team then adds implementations for the API.
In order to be able to re-generate the server at any time without affecting the implementations, the delegate pattern is utilized and will be further explained below.
Navigate to the project root using a terminal and execute the following command to generate the server code.
The generated code can again be found under the target folder.
After completing the generation, the API and model packages are copied to the server.petstore
package. The implementations will be kept in the controller
package and have to implement the delegate interfaces. The delegate interfaces define default implementations for all APIs and return a HTTP 501 (Not Implemented) if not overridden.
The PetApiController
uses either the default PetApiDelegate
if we do not define our own. However, if we define our own with custom implementations as depicted below, it will be automatically used.
Note that our delegate implementation has to be a spring bean and the @Component
annotation is added on top of the class.
The delegate pattern effectively separates the definition of the API from its implementation and both can be modified independently. The default delegate, API and models can be re-generated without affecting the implementation and vice-versa.
Run application
Use below command to start the application. A swagger UI web interface can be accessed under http://localhost:8090/openapi to inspect and interact with the REST API.
Run tests
Conclusion
In this article, we've demonstrated how to speed up development with Spring Boot using client- and server code generation. Using these techniques has helped our team of experts at PALO IT to rapidly develop our own REST APIs and integrate external ones with our applications. By openly sharing our approach to development, we hope that it will benefit you, our dear readers, and spark some interest in our other practices. Open source ftw!
Get in touch
PALO IT is always looking for passionate developers to join our team. Are you interested in learning, coding, and applying cutting edges technologies to empower our customers and make the world a better place? Don't think twice and apply here!
Interested in developing your own REST APIs? Tap into our team of experts, and let's build something awesome, together.