Automate Java SDK creation using OpenAPI! Build, maintain, and deploy high-quality SDKs using best practices for API integration and developer experience.
Aleks
Created: September 7, 2024
Updated: September 27, 2024
Our mission is to make the Internet a safer place, and the new login standard passkeys provides a superior solution to achieve that. That's why we want to help you understand passkeys and its characteristics better.
APIs are one of the most important components in communication between services in modern software, and the OpenAPI Specification has become the go-to standard for defining them. But while building an API might seem straightforward, offering a smooth developer experience often depends on the availability of SDKs (Software Development Kits). SDKs simplify API integration by providing pre-built, language-specific libraries that developers can use to interact with APIs more efficiently.
Creating and maintaining SDKs manually for multiple programming languages can quickly become a time-consuming task. That's where automating the process as much as possible comes in handy. By leveraging the OpenAPI standard, you can automate the generation of SDKs, reducing maintenance time and ensuring consistency across different platforms.
In this guide, we’ll focus on how to build a Java SDK based on an OpenAPI specification. By the end of this tutorial, you’ll have a clear understanding of the following:
We'll use Corbado’s passkey-first Java SDK as an example, guiding you through the practical steps and considerations involved in creating a professional, user-friendly SDK.
Recent Articles
⚙️
How to Implement Passkeys in Java Spring Boot Apps
⚙️
How to Build a Vanilla JavaScript Passkey Login
⚙️
How to Implement Passkeys in Next.js Apps
⚙️
Next.js Login Page: How to Implement Auth in Next.js
⚙️
Why Passkey Implementation is 100x Harder Than You Think – Misconceptions, Pitfalls and Unknown Unknowns
The prerequisites are pretty simple. You need a backend services that exposes an API. This API should be a RESTful API and you should have an OpenAPI specification of it available.
The first step in building a Java SDK from an OpenAPI specification is to use an OpenAPI generator to create a client SDK. The OpenAPI generator simplifies the process by automatically generating client-side code that interacts with your API.
Ideally, the generated client SDK should be placed in a separate project or repository. This ensures clean separation from your main application, helping to simplify dependency management. Generated SDKs often include third-party libraries that might not align with the dependencies used in your core project.
Subscribe to our Passkeys Substack for the latest news, insights and strategies.
SubscribeBest Practice: Avoid Modifying Generated Code
It’s best practice to avoid manually modifying the generated code. Once you start editing the generated SDK code, it becomes difficult to keep up with future updates or regenerate the SDK when your OpenAPI specification changes. Instead, any custom functionality should be built on top of the generated code, not directly within it.
If you're concerned about exposing the complexities of the generated code to developers, decouple the generated code from your SDK interface. This way, the complexity remains hidden, and your SDK provides a clean, simple interface for developers to use.
When building a Java SDK from an OpenAPI specification, it’s important to first familiarize yourself with existing SDKs that can serve as role models (if they exist - in other cases you need to define the requirements for the SDK).
For Corbado’s Java Passkeys SDKs, two key scenarios include session validation and extracting additional user information. These features are important for developers integrating user authentication into their applications.
The goal of the SDK is to provide more than just a generated client. While a simple client offers basic API interaction, a well-built SDK enhances the developer experience by offering:
Become part of our Passkeys Community for updates and support.
JoinAn essential part of building the Corbado SDK is understanding how JSON Web Tokens (JWT) and JSON Web Keys (JWK) are handled, as these are used for session validation. You’ll want to:
A JWT validation process could include validating the signature, checking token expiration, and handling JWK
errors with custom exceptions like JWTVerificationException
or JwkException
.
Example endpoint in Spring Boot using Session Service:
Providing clear unit tests for valid and invalid tokens can demonstrate how these validations work in practice. This not only ensures robustness but also offers developers a clear example of how to handle JWTs in their applications. You can take a look at SessionServiceTest as an example.
Error handling is crucial to any SDK. Some of the key exceptions in our example include:
The SDK also takes care of validating input on the client side to avoid sending invalid data to the server. Common validations include:
pro-
and apiSecret starting with corbado1_
).Follow Java best practices for project structure and code quality is essential to ensure that your library is easy to use, maintain, and integrate. Below are some recommendations for structuring your SDK project and maintaining clean, readable code, with specific examples for Java.
A well-structured project is crucial for making your Java SDK standalone and easily importable by other developers. Look at this repository on GitHub, which provides sample project layouts that follow best practices. Organizing your SDK into modular components with clear directory structures helps developers navigate the code more easily and import your SDK without hassle.
To maintain clean, standardized code, it’s important to use modern formatters and linters. These tools ensure that your code adheres to established guidelines, making it more readable, consistent, and less prone to errors. Below is a recommendation for Java:
Clean code is critical for any SDK, but it becomes even more important in smaller projects where every line of code has the potential to impact usability and maintainability.
To build a nice Java SDK, look at how established companies approach SDK development. For example, Stripe is known for having one of the most well-documented and widely used SDKs across multiple languages. Studying their approach can teach you the following:
Examining how SDKs like Stripe structure their projects can give you insights into creating a clean, modular project architecture. For example, in Java, Stripe uses the Builder Pattern for their client configuration classes, which is particularly useful when dealing with many optional parameters. This pattern ensures that your SDK’s API remains flexible while maintaining readability and simplicity for developers. If your SDK has configuration-heavy components, adopting this pattern might be ideal.
One of the key takeaways from analyzing successful SDKs is the importance of comprehensive and accessible documentation. The README file is often the first interaction a developer has with your SDK, so it should include:
Are your users passkey-ready?
Test Passkey-ReadinessBuilding an SDK requires selecting the right libraries to ensure compatibility, maintainability, and ease of use. The stack you choose will directly affect how well your SDK integrates into other projects and how easy it is for developers to adopt it. Let’s break down the key components you’ll need to consider based on the insights gathered from previous sections and established best practices.
For Java, the two main build tools to consider are Maven and Gradle. Both are widely used, but your choice depends on the specific needs of your SDK:
Your SDK will need a reliable HTTP client to interact with APIs. For Java, consider HttpClient from the standard library or popular libraries like OkHttp if you need more flexibility.
For JSON parsing, both Jackson and Gson are widely used in Java. Jackson is often favored for its extensive features and performance, while Gson is lighter and simpler to use. If your SDK needs advanced serialization features or works with complex JSON structures, Jackson is likely the better choice.
For logging, Java developers often choose between SLF4J with Logback or Log4j. SLF4J provides an abstraction layer that allows you to switch between logging implementations without changing your code. Coupled with Logback, it offers high performance and flexibility. Log4j is another solid option but has become less popular due to past security vulnerabilities.
When handling errors, it's important to consider how your SDK will interact with external systems. For example, using a
custom exception like CorbadoServerException
can provide meaningful error messages when something goes wrong during
API
calls. This is especially useful when developers need to debug integrations with your SDK.
Testing is critical to maintaining the reliability of your SDK. For Java, tools like JUnit and Mockito are standard for unit testing and mocking. JUnit provides a simple, structured way to write tests, while Mockito allows you to mock objects in tests, which is particularly useful for API-driven SDKs where you need to simulate API responses.
Continuous integration and delivery (CI/CD) are essential for ensuring that your SDK is always deployable and free of bugs. Popular options include:
Whichever you choose, make sure your pipeline includes automated testing, linting, and code analysis.
For Corbado's Java SDK, we used the following CI/CD process:
The SDK should be compatible with most used versions of the language. CI/CD can easily do that with matrix feature that allows you to run multiple jobs in parallel with different configurations.
This often helps identify compatibility or configuration issues that may not be apparent locally if the build or tests are failing.
Simplify the deployment process for other developers by following these steps: After build, lint and test you can choose to deploy the application on some events (for example on version tag in Java SDK). No extra steps needed. For Java, we needed to:
Libraries like Lombok can improve development efficiency and reduce boilerplate code. It can greatly reduce boilerplate code by automatically generating getters, setters, constructors, and builders at compile time using annotations.
Managing dependencies is a key aspect of maintaining a clean, lightweight SDK. Avoid adding unnecessary dependencies, as
they can bloat your package and potentially introduce security vulnerabilities. Be mindful of separating compile-time, runtime, and test dependencies. For example, in Maven, use the <scope>
tag to define when a dependency is
required.
When selecting libraries, also take into account security vulnerabilities and version compatibility. For example, older versions of dependencies may no longer receive security updates, which can introduce risks to your users. Be cautious with which versions of dependencies you support and ensure that your SDK runs on the most commonly used versions of the language.
Want to find out how many people can use passkeys?
View Adoption DataWhen building an SDK, ensuring a smooth and collaborative development process is key to long-term success. This requires setting up consistent configurations, automating processes where possible, and simplifying release management to make it easy for teams to work together and ship updates.
A full CI/CD pipeline is essential for ensuring that all code is automatically tested and analyzed before it reaches production. However, to make collaboration as seamless as possible, every developer working on the SDK should use the same coding standards and tools, regardless of their machine or development environment.
By sharing these configuration files through version control, developers won’t need to reconfigure their IDEs or tools every time they clone the project. This ensures consistency in code quality, reduces friction in onboarding new developers, and prevents errors caused by mismatched environments.
If possible, provide IDE-specific configuration files for your language and preferred IDEs, such as Eclipse, IntelliJ IDEA, or VS Code. This will help ensure that developers are using the same environment settings, making
collaboration more efficient. For Java projects, you could include an .idea
folder for IntelliJ IDEA or .project
for
Eclipse in your repository to share project settings.
Providing pre-configured settings files simplifies the development process by ensuring that all contributors work in an optimized and uniform environment.
Managing the SDK version should be straightforward and clear. If your versioning process is complicated or error-prone, it can lead to mistakes during release preparation, resulting in inconsistencies across different environments.
A best practice is to make the VERSION file the single source of truth for your SDK version. This simplifies the release process by ensuring that all tooling, documentation, and package metadata pull from the same version reference. By keeping the version in one place, you reduce the risk of mismatches between what’s deployed and what’s documented.
For example, you can update the VERSION file automatically during your CI/CD pipeline to reflect the latest release version. This practice can also trigger other actions, such as updating changelogs and pushing the latest version to package managers like Maven Central.
Automation plays a key role in maintaining ease of collaboration. Set up pre-commit hooks that run linters, formatters, and tests before changes are committed to the codebase. This will ensure that only clean, validated code is pushed, reducing the chance of introducing errors into the shared repository.
For example:
Testing is a critical part of building any SDK, ensuring that it works as expected and is reliable in production environments.
When building your SDK, it’s efficient to start by referencing existing tests from similar SDKs. For example, if Corbado already has SDKs written in other languages like PHP, use those as a baseline. You can adapt and extend the existing test cases to match the language-specific features of your new SDK.
To ensure that your SDK delivers a great developer experience, it's essential to approach testing from the perspective of an external developer who will be using it. Set up the SDK as if you were an external user, integrating it into a sample application to identify any pain points or unclear areas.
Clear, concise, and well-structured documentation is crucial to the success of any SDK. It ensures that developers can easily understand how to implement your SDK, use its features, and troubleshoot issues. The documentation should not only provide a comprehensive overview of the SDK's capabilities but also guide developers through its use with real-world examples.
Want to experiment with passkey flows? Try our Passkeys Debugger.
Try for FreeYour documentation must clearly outline what is required for each function and configuration field. Developers need to know:
To ensure consistency, the information in your documentation should be automatically generated from your code annotations, such as Javadoc for Java. This ensures that the documentation is always up-to-date and accurately reflects the SDK’s implementation.
Your documentation should provide detailed explanations of what each function and class does. This includes:
By providing clear and descriptive documentation, you lower the barrier to entry for developers who are new to your SDK, making it easier for them to understand how to integrate it into their projects.
Beyond formal documentation, clear code comments are essential to help future developers (including your team) understand the logic behind certain code decisions. Use standard commenting practices in your codebase to:
Good commenting practices help bridge the gap between the code and its documentation, making the project easier to maintain and extend.
Building a Java SDK from an OpenAPI specification involves several key steps, from generating the client to ensuring ease of use for developers through proper project structure, best practices, and thorough testing. By focusing on a clean, consistent technology stack, adopting industry-standard tools and libraries, and providing robust documentation, you create an SDK that’s intuitive, reliable, and easy to integrate. Following these best practices not only streamlines development but also positions your SDK as a professional tool that developers can confidently use in production.
Table of Contents
Enjoyed this read?
🤝 Join our Passkeys Community
Share passkeys implementation tips and get support to free the world from passwords.
🚀 Subscribe to Substack
Get the latest news, strategies, and insights about passkeys sent straight to your inbox.
We provide UI components, SDKs and guides to help you add passkeys to your app in <1 hour
Start for free
Recent Articles
How to Implement Passkeys in Java Spring Boot Apps
Nicolai - September 19, 2023
Symfony Passkeys: How to Implement Passkeys in PHP Symfony
Lukas - April 17, 2023