If you are developing the backend and frontend part of an application you know that it can be tricky to keep the data models between the backend & frontend code in sync. Luckily, we can use generators that generate server stubs, models, configuration and more based on a OpenAPI specification.
In this article, I want to demonstrate how you can implement such an OpenAPI generator in a demo application with an Angular frontend and a Spring Boot backend.
The Demo Application
For this article, I have created a simple demo application that provides a backend REST endpoint based on Spring Boot that returns a list of gaming news. The frontend based on Angular requests this list from the backend and renders the list of news.
The source code is available on GitHub.
The Angular frontend was generated with the Angular CLI and the Spring Boot backend with Spring Initializr.
OpenAPI
The OpenAPI specification is defined as
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
Such an OpenAPI definition can be used by tools for testing, to generate documentation, server and client code in various programming languages, and many other use cases.
The specification has undergone three revisions since its initial creation in 2010. The latest version is 3.0.2 (as of 02.03.2020).
OpenAPI Generator
In this article, I want to focus on code generators, especially on the openapi-generator from OpenAPI Tools.
This picture taken from the project's GitHub repository shows the impressive list of supported languages and frameworks:
For this article's demo project the @openapitools/openapi-generator-cli package is used to generate the Angular code via npm and openapi-generator-gradle-plugin to generate the Spring code using Gradle.
OpenAPI Schema Definition
The OpenAPI code generator needs a yaml
schema definition file which includes all relevant information about the API code that should be generated.
Based on the official petstore.yaml example I created a simple schema.yaml
file for the demo news application:
Let's take a look at the most important parts of this file:
openapi
: The version of the OpenAPI specificationservers -> url
: The backend URLinfo
: General API informationpaths
: This section defines the API endpoints. In our case, we have one GET endpoint at/news
which returns a list of articles.components
: Describes the structure of the payload
For more information about the schema definition, you can take a look at the basic structure or at the full specification (in this case for v3).
Generate backend code based on this schema
In this section, I will demonstrate how the backend code for Spring Boot can be generated based on our schema definition.
The first step is to modify the build.gradle
file:
As you can see, two new Gradle tasks are defined: openApiValidate
and openApiGenerate
. The first task can be used to validate the schema definition, and the second task generates the code.
To be able to reference the generated code in the Spring Boot application it needs to be configured as sourceSet
. Additionally, it is recommended to define compileJava.dependsOn('openApiGenerate')
to ensure that the code is generated each time the Java code is compiled.
For the backend code, we just want to generate models and interfaces, which is done in configOptions
by setting interfaceOnly: "true"
.
Detailed documentation about all possible configuration options can be found at the official GitHub repository.
Running ./gradlew openApiGenerate
produces this code:
Make sure to add this folder with generated code to your .gitignore
file and exclude it from code coverage & analysis tools.
At this point, we can use the generated code in our Spring Boot backend. The first step is to create a Controller
which implements the generated OpenAPI interface:
This GET
endpoint is available at /api/news
and returns a list of news that is provided by NewsService
which just returns a dummy news article:
@CrossOrigin(origins = "http://localhost:4200")
allows requests from our frontend during local development and @ApiOperation("Returns list of latest news")
is used for Swagger UI which is configured in SpringConfig.jav.
Finally, we can run the backend using ./gradlew bootRun
and trigger the news endpoint
which returns this JSON payload:
Generate frontend code based on this schema
In this section, I want to describe how Angular code can be generated based on our schema definition.
First, the OpenAPI generator CLI needs to be added as npm dependency:
Next step is to create a new npm script in package.json
that generates the code based on the OpenAPI schema:
This script generates the code inside the frontend/build/openapi
folder:
Make sure to add this folder with generated code to your .gitignore
file and exclude it from code coverage & analysis tools.
It is also important to run this code generation script each time you run, test or build your application. I would, therefore, recommend using the pre
syntax for npm scripts:
Finally, we can import the generated module in our Angular application in app.module.ts
:
Now we are ready and can use the generated code in the frontend part of the demo application. This is done in app.component.ts
:
Last step is to use the AsyncPipe
in the HTML to render the articles:
If your backend is running locally, you can now serve the frontend by calling npm start
and open a browser on http://localhost:4200
and you should see the dummy article:
Alternative
Of course, it is also possible to generate the frontend code if you have no control over the backend code but is supports OpenAPI.
It is then necessary to adjust the npm script to use the backend URL instead of referencing the local schema file:
Conclusion
Having one file to define your API is helpful and can save you a lot of development time and prevent possible bugs caused by different models or API implementations in your frontend and backend code.
OpenAPI provides a good specification with helpful documentation. Additionally, many existing backends use Swagger for their API documentation, therefore it should also be possible to use this code generation for frontend applications where you cannot to modify the corresponding backend.
Due to the many supported languages and frameworks, it can be used in nearly every project, and the initial setup is not very hard.
In my current project, we use OpenAPI code generation for every new project and are very happy with it.
Let me know in the comments what you think about this approach and if you also have some OpenAPI experiences to share.
Sending Message To Specific Anonymous User On Spring WebSocket
In my current, I had the opportunity to develop a new application based on Vue.js in the frontend and Spring Boot in the backend. The backend should send updates to the frontend via a WebSocket connection so that users do not need to refresh the website to see the latest information.
Property Based Testing With Typescript
In my current project my colleague Michael Seifert introduced property based testing in our Python codebase. It was the first time I heard about it and it sounded fascinating, so I wanted to also implement it in our frontend code based on Vue.js with Jest as testing framework and TypeScript as programming language.