python sdk openapiEngineering

How to Build a Python SDK based on OpenAPI

Automate Python SDK creation using OpenAPI. Build, maintain, and deploy high-quality SDKs using best practices for API integration and developer experience.

Blog-Post-Author

Aleks

Created: September 10, 2024

Updated: September 10, 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.

1. Introduction#

APIs play a crucial role in modern software development, serving as the bridge for communication between services. The OpenAPI Specification has emerged as the standard for defining these APIs. While building an API is often the first step, providing a seamless developer experience requires more — that's where SDKs (Software Development Kits) come into play. SDKs enable easier API integration by offering pre-built, language-specific libraries that developers can directly use to interact with APIs.

Maintaining SDKs across multiple programming languages manually can quickly become overwhelming. This is where automation can be a game changer. Leveraging the OpenAPI standard, you can automate SDK generation, saving time, and ensuring that your SDKs are consistent across different platforms.

In this guide, we’ll walk you through how to build a Python SDK based on an OpenAPI specification. By the end of this tutorial, you will understand:

  • How to build a Python SDK from an OpenAPI specification.
  • The steps to go from an OpenAPI file to a fully functional, deployable Python SDK.
  • Best practices for building and maintaining SDKs.

For this guide, we’ll reference Corbado’s passkey-first Python SDK as an example, showing you the practical steps and considerations for creating a developer-friendly SDK.

2. Prerequisites#

The prerequisites for this guide are straightforward. You’ll need a backend service that exposes an API. This API should be a RESTful API, and it’s essential that you have an OpenAPI specification available for it.

3. Use an API Generator to Create a Client#

The first step in building a Python 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, tailored specifically for Python.

To maintain clean project structure, it’s best to place the generated client SDK in a separate project or repository. This helps with dependency management by isolating the generated SDK from your main application, as generated SDKs often include third-party libraries that may not align with the dependencies used in your core project.

Substack Icon

Subscribe to our Passkeys Substack for the latest news, insights and strategies.

Subscribe

Best Practice: Avoid Modifying Generated Code

It’s generally recommended to avoid making manual changes to the generated code. Once you start modifying the generated SDK code, it becomes challenging to keep track of updates or regenerate the SDK when your OpenAPI specification evolves. Instead, any custom functionality or enhancements should be implemented separately from the generated code.

If you’re worried about exposing the complexities of the generated code to end-users, you can decouple the generated code from your SDK interface. This way, the complexity stays hidden, while the SDK provides a clean, user-friendly interface for developers.

4. Understand the SDK Requirements#

When building a Python SDK from an OpenAPI specification, it’s crucial to first understand what features the SDK should provide. If there are existing SDKs in the ecosystem, they can serve as role models. Otherwise, you’ll need to define the SDK’s requirements from scratch.

4.1 Key Use Cases: Session Validation and User Information Extraction#

For Corbado’s Python Passkeys SDK, two key use cases include session validation and extracting additional user information. These features are important for developers who are integrating user authentication into their applications.

passkeys python sdk

4.2 Purpose of the SDK: Why Not Just Use a Generated Client?#

The goal of the SDK is to offer more than just a generated client. While a basic client provides interaction with the API, a well-designed SDK enhances the developer experience by offering:

  • A simple, easy-to-install library for connecting to the backend.
  • Meaningful error handling, making debugging easier for developers.
  • Straightforward configuration, allowing developers to start quickly with minimal setup.
  • Well-documented examples for using all functionality (often supported by unit tests).
  • A lower barrier to entry for developers trying out the service for the first time.
Slack Icon

Become part of our Passkeys Community for updates and support.

Join

4.3 JWT/JWK Handling and Validation#

A key part of building the Corbado Python 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:

  • Familiarize yourself with JWT/JWK concepts
  • Search for available JWT libraries for Python

In Python, JWT handling is typically done with libraries like pyjwt.

pyjwt

It’s important to provide unit tests to demonstrate how JWT validation works for both valid and invalid tokens. This not only ensures that the SDK is robust, but also helps developers understand how to use it effectively in their own applications. You can take a look at the test_session_service.py as an example for Python.

4.4 Handling Errors in the SDK#

Error handling is a critical component of any SDK. In our Python SDK example, some key exceptions include:

  • server_exception: This is raised when the backend API responds with an HTTP status code other than 200. The exception includes deserialized error responses, giving developers detailed information about the error.
  • standard_exception: This exception is used for client-side errors that are unrelated to the backend, such as invalid input or configuration issues.

By providing clear, well-defined exceptions, the SDK helps developers identify and resolve issues quickly, making the integration process smoother.

4.5 Implementing Client-Side Validation#

In addition to server-side validation, the SDK also handles client-side validation to ensure that only valid data is sent to the server. Common types of validation include:

  • URL validation: The SDK ensures that provided URLs follow the correct format, preventing malformed URLs from being sent.
  • String constraints: For example, user IDs must not be empty or contain invalid characters.
  • Configuration validation: Certain configuration fields, such as projectId and apiSecret, must adhere to specific patterns. For instance, projectId should start with pro-, and apiSecret should start with corbado1_.

By enforcing these validations on the client side, the SDK minimizes the chances of invalid data reaching the server, ensuring a more robust and reliable integration experience for developers.

5. Identify Best Practices for Python#

Following Python best practices for project structure and code quality is crucial to ensure your SDK is easy to use, maintain, and integrate. Below are some recommendations for structuring your Python SDK project and maintaining clean, readable code, with Python-specific examples.

5.1 Structuring Your Project for Ease of Use#

A well-structured project is essential to making your Python SDK standalone and easily installable by other developers. You can refer to nedbat/pkgsample: A simple example of how to structure a Python project, which provides best practices for Python project layouts. Organizing your SDK into modular components with a clear directory structure helps developers navigate the codebase easily and integrate your SDK without hassle.

5.2 Use Modern Formatters and Linters#

To maintain clean, standardized code, it’s important to use modern formatters and linters. These tools ensure your code adheres to Python's style guidelines, making it more readable, consistent, and less prone to errors. Below are recommendations for Python:

pylance

  • mypy: A static type checker for Python that helps catch type-related bugs before runtime. Find more details here.

mypy

  • Flake8: A tool for enforcing Python’s PEP 8 style guide and catching potential issues. Learn more about it here.

flake8

  • isort: A tool that automatically sorts Python importsto ensure they are organized and follow PEP 8 guidelines.

isort

  • Black Formatter: A strict code formatter that enforces consistent Python code style based on PEP 8 automatically.

5.3 Keep Code Clean and Maintainable#

Clean and maintainable code is critical for any SDK, and it's especially important in Python, where readability and simplicity are core principles. Use descriptive variable names, adhere to Python's Zen (import this), and follow the DRY (Don't Repeat Yourself) principle to minimize code duplication. Also, make sure your SDK is well-documented with docstrings and examples to help developers understand how to use it effectively.

python-zen

6. Identify Best Practices and Established Coding Standards for SDK Development#

To build a well-designed Python SDK, it's important to look at how established companies approach SDK development. Stripe, for example, is known for having some of the most well-documented and widely used SDKs across multiple languages. By studying their approach, you can learn the following key practices:

  • CI/CD Structure: Stripe uses an efficient continuous integration and continuous delivery (CI/CD) pipeline to automate testing and deployment. Understanding their setup can help you build a basic CI/CD structure for your Python SDK, ensuring that it is always tested and ready for production.
  • What to Test in CI/CD: Observing how major SDKs like Stripe structure their test suite can help you identify critical areas to test, such as unit tests, integration tests, and API contract validation. Testing should cover core functionality, edge cases, and backward compatibility.
  • Python Version Compatibility: Ensuring compatibility with multiple versions of Python is crucial for a widely adopted SDK. For instance, your SDK might support Python 3.7 and above, depending on user requirements and deprecations in earlier versions. As of September 2024, according to statistics a lot of websites are still using Python 3.6 and 3.7. However, that may not be not the versions you want to support if you take into consideration:
    • which projects would want to use your SDK (probably rather modern than legacy systems)
    • older versions do not have security support
    • other dependencies you may want to include could (and often will) end the support of EOL language versions.
    • you may miss important language features like typing support for Python that will make your code safer and easier to maintain / understand.

python-versions

  • Linting and Code Static Analysis: Stripe implements strict linting and static code analysis to maintain high code quality. Tools like Flake8 and Pylint can be integrated into your CI pipeline to catch potential issues early.

6.1 Code and Project Structure#

Studying the project structure of successful SDKs like Stripe can provide valuable insights into creating a clean, modular architecture. For example, in Python, Stripe uses the Builder Pattern to manage complex client configurations. This is especially useful when your SDK needs to handle many optional parameters. The Builder Pattern ensures that your SDK remains flexible while keeping the code readable and user-friendly for developers. If your SDK has configuration-heavy components, adopting this pattern could simplify its API.

6.2 Documentation Best Practices#

A key lesson 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:

  • Clear setup instructions: A step-by-step guide on how to install and configure the SDK, reducing friction for developers.
  • Code examples: Showcase core use cases, such as authentication, session handling, and error management, to give developers quick insights into how the SDK can be used.
  • Links to further documentation: Provide links to more detailed documentation or advanced use cases for developers who need to dive deeper.

Ensuring that your documentation is beginner-friendly, while also addressing more advanced developer needs, can significantly enhance the adoption and usability of your SDK.

Analyzer Icon

Are your users passkey-ready?

Test Passkey-Readiness

7. Determine Your Tech Stack and Useful Libraries#

Building a Python SDK requires selecting the right libraries and tools to ensure compatibility, maintainability, and ease of use.

7.1 Build Tools and Dependency Management#

For Python, the most common tools for managing dependencies and building your SDK are setuptools, pip-tools and poetry:

  • setuptools: A widely used tool for packaging Python projects, setuptools is reliable and integrates seamlessly with PyPI (Python Package Index) for distributing your SDK. It is simple to use and a well-established choice in the Python ecosystem. The setup.py file is used for defining your package dependencies and installation process. However, it will be deprecated soon by pyproject.toml.

setuptools

  • pip-tools: Helps manage your requirements.txt file and generate a locked dependency list.
  • Poetry: If you want a more modern approach to dependency management, Poetry offers advanced features like dependency resolution, virtual environments, and publishing tools, all in one. It simplifies managing both your package and its dependencies.

7.2 HTTP Client and JSON Parsing#

Your SDK will require a reliable HTTP client to interact with APIs. In Python, there are several popular choices:

  • requests: The most widely used HTTP client in Python, requests is known for its simplicity and ease of use. It’s the go-to choice for most SDKs, offering features like session management, authentication handling, and timeouts with minimal setup.

requests

For JSON parsing, Python has built-in support via the json module, but if you need more advanced features, you can use ujson for faster performance or simplejson for enhanced compatibility.

  • json: Python’s standard json library is sufficient for most use cases.
  • ujson: UltraJSON offers faster serialization and deserialization for large data sets.
  • simplejson: simplejson offers additional flexibility, such as working with Python’s Decimal class or handling non-standard JSON input.

7.3 Logging and Error Handling#

For logging in Python, the logging module in the standard library is the most common choice. However, for more complex needs, structured logging libraries like structlog can be used:

  • logging: The built-in logging module is sufficient for most SDKs and is highly customizable. You can easily configure different log levels and formats for better debugging and tracking.
  • structlog: If you need structured logging, structlog provides a more flexible and powerful approach. It allows you to log structured data (like JSON) and is great for modern logging systems.

7.4 Testing Frameworks#

Testing is crucial for ensuring the reliability of your SDK. For Python, the most common tools include pytest and unittest. pytest is particularly popular for its simplicity, flexible plugins, and fixtures, making it easier to write and organize tests. You can also use unittest.mock to mock objects and functions, which is especially useful when testing API-driven SDKs that need to simulate API responses.

  • pytest: A powerful and flexible testing framework that makes writing tests concise and expressive.
  • unittest: The built-in testing library in Python, which provides support for test discovery and mocking.

7.5 CI/CD Integration#

Continuous integration and delivery (CI/CD) are essential for ensuring that your SDK is always deployable, tested, and bug-free. Some of the most popular CI/CD options include:

  • GitHub Actions: Integrated into GitHub, GitHub Actions is a popular choice due to its seamless integration with GitHub repositories. It is highly customizable and free for open-source projects.
  • CircleCI: CircleCI is another cloud-based CI/CD service that integrates well with GitHub and Bitbucket and supports multiple Python versions.

When setting up your CI pipeline, ensure it includes automated testing, linting, and code analysis.

For Corbado's Python SDK, we used the following CI/CD process:

  1. Set up a CI workflow in GitHub Actions.
  2. Include automated tests for different Python versions using the matrix feature.
  3. Use twine to automate the deployment process to PyPI after passing all tests.
  4. Make sure the project complies with PyPI packaging requirements.
  5. Use GPG signing for package integrity if necessary.

7.6 Optional Tools#

Tools like Pydantic can improve development efficiency by enforcing data validation and management. Pydantic automatically validates and parses incoming data, reducing the need for manual error handling and making your SDK more robust. We have used Pydantic for:

  • Type Enforcement
  • Custom Validation
  • Type Annotations for cleaner, more expressive code
  • Data Classes

Example code with field constraints:

backend_api: str = "https://backendapi.cloud.corbado.io/v2" short_session_cookie_name: str = "cbo_short_session" cname: Optional[Annotated[str, StringConstraints(strip_whitespace=True, min_length=1)]] = None _issuer: Optional[Annotated[str, StringConstraints(strip_whitespace=True, min_length=1)]] = None

7.7 Security and Compatibility Concerns#

When choosing libraries for your SDK, it’s important to consider security vulnerabilities and version compatibility. Regularly review your dependencies for potential security risks and ensure that your SDK runs on commonly used versions of Python. Use tools like safety to scan your dependencies for known security vulnerabilities and make sure to update libraries as needed.

StateOfPasskeys Icon

Want to find out how many people can use passkeys?

View Adoption Data

8. Ease of Collaboration and Development#

When building a Python SDK, ensuring a smooth and collaborative development process is key to long-term success. This involves setting up consistent configurations, automating processes where possible, and simplifying release management to make it easy for teams to work together and ship updates efficiently.

8.1 Consistent Project Configuration Across All Machines#

A well-configured CI/CD pipeline ensures that all code is automatically tested and analyzed before it reaches production. However, to make collaboration as seamless as possible, all developers working on the SDK should use the same coding standards and tools, regardless of their machine or development environment.

By sharing configuration files, such as .editorconfig, pyproject.toml, or .flake8 through version control, developers won’t need to manually configure their IDEs or tools. This ensures consistent code quality, reduces onboarding friction, and prevents errors caused by differing development environments.

8.2 Sharing IDE Configuration#

If possible, provide IDE-specific configuration files for your preferred editors, such as PyCharm, VS Code, or Sublime Text. This ensures that developers work with the same settings, making collaboration more efficient. For Python projects, you might include .vscode settings or PyCharm’s .idea folder in the repository, sharing project configurations like formatting rules, linters, and debugging setups.

Providing pre-configured settings files makes the development process easier by ensuring all contributors work in a consistent, optimized environment.

8.3 Version Management and Simplified Releases#

Managing SDK versions should be simple and reliable. A complicated or error-prone versioning process can lead to mistakes during releases, causing inconsistencies between environments.

A best practice is to maintain a single source of truth for your SDK version in a dedicated VERSION file or by utilizing pyproject.toml or setup.py to handle versioning automatically. This simplifies the release process by ensuring that all tooling, documentation, and package metadata pull from the same version reference.

Automate version updates during your CI/CD pipeline to reflect the latest release, updating the changelog and pushing the latest version to package managers like PyPI.

8.4 Automating Development Workflows#

Automation is key to maintaining ease of collaboration. Set up pre-commit hooks that automatically run linters, formatters, and tests before changes are committed. This ensures that only clean, validated code reaches the repository, reducing the chance of introducing errors into the shared codebase.

9. Testing#

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 Python SDK.

  • Start by examining the key use cases covered by the existing tests, such as session validation, error handling, and JWT verification.
  • Replicate those tests in your Python SDK, making adjustments for language-specific differences.
  • If your SDK introduces new functionality, be sure to add additional tests that cover these features.

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.

Recommended Testing Frameworks for Python:

  • pytest: Use pytest for its flexibility and ability to handle complex test cases with minimal boilerplate.
  • unittest.mock: Utilize this module for mocking external services, allowing you to test your SDK without making real API calls.

10. Documentation#

Clear, concise, and well-structured documentation is crucial to the success of any SDK.

Debugger Icon

Want to experiment with passkey flows? Try our Passkeys Debugger.

Try for Free

10.1 Ensure Users Understand Function Arguments and Configuration Fields#

Your documentation must clearly outline what is required for each function and configuration field. Developers need to know:

  • Which arguments are required: Clearly specify which function parameters or configuration fields are mandatory and which are optional. Also, include default values for any optional parameters, if applicable.
  • What constraints apply to each field: Provide details about constraints like whether a field is nullable, its maximum or minimum length, and if it must follow a specific format (e.g., email, URL). These details help avoid confusion and potential errors during implementation.

To ensure consistency, the information in your documentation can be automatically generated from your code using tools like Sphinx or pdoc for Python, ensuring that the documentation is always up-to-date and reflects the SDK’s implementation accurately.

10.2 Clearly Explain Functions, Classes, and Configuration Parameters#

Your documentation should provide detailed explanations of what each function and class does. This includes:

  • The purpose of the function or class.
  • The parameters it expects and their data types.
  • The expected output or return type.
  • Any side effects the function may have (e.g., database changes, API calls).
  • Specific error conditions or exceptions the user should handle.

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 integrate it into their projects.

10.3 Follow Standard Code Commenting Practices#

In addition to formal documentation, clear code comments are essential for helping future developers (including your team) understand the logic behind certain code decisions. Use standard commenting practices in your codebase to:

  • Explain complex logic or edge cases that might not be immediately obvious.
  • Mark TODOs or areas that need further attention.
  • Provide additional context when handling errors or exceptions.

Good commenting practices bridge the gap between code and documentation, making the project easier to maintain and extend.

11. Conclusion#

Building a Python 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.

Share this article


LinkedInTwitterFacebook

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