🎒 Resources
- GitHub Repository for my Sandbox REST API
- OpenAPI Initiative
- OpenAPI Library for Spring Boot
- Online Swagger Editor
The SDK Generation Dilemma
You might wonder: why bother with programmatically generating SDK clients? Isn’t it enough to pick one from the available HTTP client libraries, create the necessary models, write request/response and error handling code, and call it a day? Well… if you ask me, the answer is a no.
The Static Approach
While this approach — let’s call it the “static” method — might work well for polyglots in small projects, one should realize very soon that supporting multiple SDK clients is a nightmare.
Even if you focus only on popular languages - like Python, JavaScript, Java, and C#, you’ll find yourself responsible for writing and maintaining code across all these clients. And let’s not overlook the documentation—you’ll need to keep that in sync as well.
Sooner or later, the SDK client code falls behind the API. No need to explain why this is a bad thing. At the end, your users are going to use a raw HTTP client manually crafting the requests, or - even worse - they will leave your service for a better supported alternative.
Since SDK clients are not rocket science, we can automate the process of generating them. All we need is a well-defined API description and a tool capable of creating SDK clients. Fortunately, OpenAPI offers a solution to this challenge.
OpenAPI Standard & SDK Generators
The OpenAPI Specification (formerly known as Swagger) is a widely adopted standard for describing REST APIs.
☝️ Important to note that OpenAPI is a specification, and not a tool. Indeed, Swagger is the name of the toolset for designing, building, and documenting your APIs.
I am not going to dive deep into the OpenAPI Specification itself. There are so many great articles and tutorials out there that cover this topic. Instead, I will focus on the SDK generation.
The OpenAPI Specification is a JSON or YAML file that describes your API. It includes information about the endpoints, the request and response bodies, the parameters, and much more.
Here is a sample OpenAPI definition for a simple REST API:
|
|
By looking at this snippet, you can easily understand what this API does: It has a single endpoint (/greeter
) that returns a greeting message in JSON format.
Since our APIs are described in a standard format, now it’s possible to generate SDK clients programmatically for various platforms. The evident solution would be to use the OpenAPI Generator, a popular tool that supports every major programming language and platform.
Naturally, I’ve chosen something different than the beaten path. As you might figure out from the title, I am going to talk about Microsoft Kiota.
Kiota what?
Kiota is a relatively new project from Microsoft. It came into my radar a few months ago, when I was reading a blog post from GitHub: Our move to generated SDKs.
Even though Kiota is not as mature as some other tools on the market, GitHub decided to use it for the following reasons:
- it’s intuitive and developer friendly (great DX 👍)
- it generates idiomatic and comprehensive SDKs
- quality is a top priority: the stable subset of supported languages provides an intuitive and consistent experience for consumers
- while it provides 100% coverage of the API, it’s also possible to narrow down the generated code to a specific subset of the API (curated, hand-picked SDKs)
Sounds promising, right? Let’s see how it looks like in practice.
Shall we?
Prerequisites
Kiota is a command line tool, so it fits perfectly into any CI/CD pipeline. Despite it’s a relatively new project, it has a decent ecosystem around it: you can use it as a CLI tool, or as a Maven plugin, or create an ad-hoc client using the Visual Studio Code extension. We cover all of these in the second part of this series.
To make it happen…
- I’ve prepared a Spring Boot based REST API with Maven
- so, the OpenAPI definition will be generated during the build process via the springdoc-openapi-maven-plugin
- finally, the Kiota SDK client will be generated using the Kiota Maven Plugin
That’s for the Java part. For Python, I will use the Visual Studio Code Extension, which is a great tool for generating SDK clients from the comfort of the IDE.
💡 Kiota really shines here, as it provides a great developer experience to generate tailor-made SDK clients for your needs.
The REST API
All right, let’s start with the REST API. I’ve created a Spring Boot application which present some quotes of famous people. I removed all the stuff which does not help the understanding of the SDK generation process, so you might find this REST API incomplete - and you are right.
Before we dive into the details, let me share the GitHub repository of the sample project. Feel free to clone it and follow along.
💡 I prepared a handy DevContainer for this project, so you don’t have to install anything on your machine. Open the project in Visual Studio Code and reopen the project in the container. Or even better: use GitHub Codespaces, and you’re good to go! 🚀
Entities, Repositories, Services and Boilerplate - The Boring Stuff
If you’ve ever authored a REST API with (or without) Spring Boot, feel free to skip ahead to the next section. Or bear with me, and let’s see what I’ve prepared for you. First, let’s delve into the essential entities needed to accurately represent quotes and their respective authors.
The Person Entity
|
|
In this code snippet, you’ll notice an unusual annotation: @Schema
. Unlike Spring Framework annotations, this one belongs to the springdoc-openapi library. Its purpose is to provide metadata for the OpenAPI definition. Here, I’ve used it to offer a concise description and an example for the properties of the Person
entity.
Additionally, take note of the Occupation
enum. It stands for a person’s occupation:
|
|
I hope it speaks for itself, so let’s move on to the Quote
entity.
The Quote Entity
|
|
As you can see, the Quote
entity has a Person
property, which represents the author of the quote via a many-to-one relationship, since a quote can have only one author, but an author can have multiple quotes.
The Repositories and Services
Since we need to persist the entities, I created a repository for each of them - they’re pretty standard Spring Data JPA repositories. I added a custom method to each Repository
, to fetch authors by their name and to fetch quotes by their author’s.
|
|
|
|
Finally, for a decent separation of concerns, I created services for the quotes, and for their authors. Look, here is the PersonService
, implemented:
|
|
The Endpoints
Let’s start with the endpoint for the quotes:
HTTP Method | Endpoint | Description |
---|---|---|
GET | /quotes | Returns a list of quotes |
GET | /quotes/{id} | Returns a quote by ID |
POST | /quotes | Upserts* a quote** |
Also, I prepared an endpoint for the authors of the quotes:
HTTP Method | Endpoint | Description |
---|---|---|
GET | /authors | Returns a list of authors |
GET | /authors/{id} | Returns an author by ID |
POST | /authors | Upserts* an author** |
*Inserts, or if it already exists, updates the quote
**requires authentication - more on this later
☝️ Note that I’ve avoided using the
PUT
andPATCH
methods — while the former is used for full updates, the latter is for partial updates. I wonder if Kiota can handle my lazy approach to REST API design. 🤔
As I mentioned earlier, the OpenAPI definition is generated by the springdoc-openapi-maven-plugin
during the build process. You can find the generated file (openapi.json
) in the target
directory.
This scenario is called code-first approach, where you begin with writing the code itself, and then generate the API definition from it. This method allows for rapid development but may lead to inconsistencies if not carefully managed.
In the professional world, you should consider the design-first approach, where the API is thoughtfully planned out using the OpenAPI Specification prior to actual development. This offers a significant advantage: you can generate SDK clients before the actual implementation, which allows - for example - your frontend team to begin working on the client side while the backend team focuses on implementation. Although it requires more effort and discipline, the productivity gains are worth it.
Given that this is a sandbox project for demonstration purposes, we are good to go with the first approach. 🤷
Annotations
Using clever annotations, you will end up with a properly documented API, which can be feed into Kiota to generate the SDK clients we need.
While these annotations may seem self-explanatory, it’s worth taking the time to explain each of them individually.
@Operation
Describes a single operation on a path. It could have more properties, but in our case, we only provide a brief summary (summary
is a required property).
@ApiResponse
This annotation is quite important for SDK generation. Usually, I would probably go with the plural form of this annotation (@ApiResponses
), but for the sake of simplicity, I focused only on the “happy path” - when our service could return all the quotes of the given author.
@Content
Pay attention at the @Content
annotation at the content
property! Kiota uses this as a hint to make the generated SDKs type-safe. Without this, the generated SDKs would return a byte array, or a Stream (depending on the language).
@ArraySchema
This one is in tandem with the aforementioned @Content
annotation. Use this, if your API operation returns a collection of an entity. In our case, I indicated that the consumer should expect a collection (well, an array) of Quote entities.
Let’s see how these annotations look like in practice. I put here the QuotesController
from my sample project - sans the imports and package declaration, for brevity:
|
|
Okay, we have the REST API ready. Now, let’s generate the OpenAPI definition file using the springdoc-openapi-maven-plugin
.
Here is the relevant part from my pom.xml
in the api
module:
|
|
This configuration tells Maven to generate the OpenAPI definition file (openapi.json
) during the build process. You can find the generated file in the target
directory of the api
module. The springdoc-openapi-maven-plugin
works a bit tricky - the generate
goal is executed during the integration test phase, that’s why we need the spring-boot-maven-plugin
to start and stop the application before and after the integration tests.
Additionally, the plugin documentation suggests that it can be configured to generate the OpenAPI definition in YAML
format, instead of JSON
. However, despite all my efforts, I couldn’t get it to work. Kiota works seamlessly with JSON, so I decided not to spend more time with the YAML option. If any readers have a solution for generating a YAML from the plugin, I’d greatly appreciate hearing about it in the comments! 🙏
The Swagger UI
I understand that following this tutorial on a theoretical level can be challenging. Fortunately, you have the option to run the api
module on your local machine and access the Swagger UI hosted by the Spring Boot application. I highly recommend doing so because it is an excellent way to gain knowledge about all the moving parts of any API.
The Swagger UI is generated automatically by the springdoc-openapi
Maven plugin - feel free to play around with the settings to customize it according to your preference.
|
|
After a few seconds, the Spring Boot application will be up and running. Navigate to http://localhost:8080/swagger-ui/index.html
in your browser, and you will see the Swagger UI. Feel free to explore the API endpoints and the models.
Thank you for your patience during this lengthy introduction. By now, I hope you have a better grasp of the REST API I’ve prepared for this demonstration. In the next part, we’ll delve into generating SDK clients using Microsoft Kiota.
Above you can find the OpenAPI definition in both JSON and YAML format for your reference. We’ll use this file in the next part to generate the SDK clients.
See you soon! 👋
Appendix A: The OpenAPI Definition, as a JSON File
|
|
Appendix B: The OpenAPI Definition, as a YAML File
|
|