Versioning Web APIs in Python
Episode #450,
published Thu, Feb 22, 2024, recorded Mon, Jan 8, 2024
You've built an awesome set of APIs and you have a wide array of devices and clients using them. Then you need to upgrade an end point or change them in a meaningful way. Now what? That's the conversation I dive into over the next hour with Stanislav Zmiev. We're talking about Versioning APIs.
Episode Deep Dive
Key Themes & Takeaways
- Why API Versioning Matters
- As soon as you have real users integrating an API, you’ll need a way to evolve that API without breaking existing client code.
- “Versioning by Suffering”: Simply duplicating entire apps or directories for each version can become overwhelming as you accumulate versions.
- APIs need a balance between flexibility and stability—Stripe exemplifies one advanced approach.
- Conway’s Law & Designing for Versioning
- Conway’s Law: Your system design mirrors your organization’s structure.
- Reverse Conway Maneuver: If you want a clean, coherent API, first define the interface you want, then structure your teams and internal processes to align with it.
- Common Versioning Approaches
- Multiple Full Deployments: Copy the entire app/DB per version (very expensive).
- Duplicating Endpoints: E.g.
/v1/getOrders
vs./v2/getOrders
—simple but not scalable if you have to maintain many versions. - Schema-Only Migrations: Keep one codebase/business logic, but transform requests/responses between old ↔ new schemas.
- Stripe’s Method: Each new version defines “gates” that convert data to the previous version (and vice versa) incrementally. Clients pinned to a specific version can remain there, while new versions continue to evolve.
- Introducing Cadwin
- Cadwin = “Cad” (Change-and-Apply DSL) + “Win” (winning at versioning?).
- Inspired by Stripe’s approach but adapted for FastAPI (and Pydantic) in Python.
- Core Ideas
- One “latest” version of your business logic.
- For each new API version, you create a small migration class describing how to convert old requests → new and new responses → old.
- Cadwin uses code generation to manage typed Pydantic schemas for every version, so your editor/IDEs can handle them correctly.
- You end up with a single codebase for core logic plus a chain of micro-conversions—much more maintainable for 10–20 versions than copying endpoints.
- Tech Details & Pros/Cons
- Minimal Performance Cost: Old versions get chain-converted, but typically only affects a small minority of calls as most clients adopt newer versions over time.
- Typed Approach: Unlike some dynamic (Ruby) solutions, Cadwin leverages Pydantic for strong schemas and mypy/VS Code for typed editor support.
- Header-based or Portal-based: By default, clients pass version info in a request header (similar to Stripe). One can also implement middlewares to automatically detect a user’s pinned version.
- Comparisons to Other Libraries
- FastAPI Versioning (DeanWay): Good for simpler or short-lived needs—duplicates endpoints as
/v1/
,/v2/
, etc. - Flask Rebar: A similar multi-endpoint duplication approach for Flask.
- Django REST Framework: Built-in versioning concepts, but you must implement details yourself.
- FastAPI Versioning (DeanWay): Good for simpler or short-lived needs—duplicates endpoints as
When to Use Cadwin vs Simpler Tools
- 2–3 Versions, Short-Term: Simple duplications (like FastAPI Versioning) might suffice.
- Many Versions, Long Support: Cadwin’s incremental “version gates” approach is more sustainable and scalable.
- API-First Companies with large client bases especially benefit from version chains that can live for years (e.g., Stripe’s model).
Links from the show
Stanislav Zmiev: github.com
Monite: monite.com
Cadwyn: github.com
Stripe API Versioning: stripe.com
API Versioning NOtes: github.com
FastAPI-Versioning: github.com
Flask-Rebar: readthedocs.io
Django Rest Framework Versioning: django-rest-framework.org
pytest-fixture-classes: github.com
Watch this episode on YouTube: youtube.com
Episode transcripts: talkpython.fm
--- Stay in touch with us ---
Subscribe to Talk Python on YouTube: youtube.com
Talk Python on Bluesky: @talkpython.fm at bsky.app
Talk Python on Mastodon: talkpython
Michael on Bluesky: @mkennedy.codes at bsky.app
Michael on Mastodon: mkennedy
Monite: monite.com
Cadwyn: github.com
Stripe API Versioning: stripe.com
API Versioning NOtes: github.com
FastAPI-Versioning: github.com
Flask-Rebar: readthedocs.io
Django Rest Framework Versioning: django-rest-framework.org
pytest-fixture-classes: github.com
Watch this episode on YouTube: youtube.com
Episode transcripts: talkpython.fm
--- Stay in touch with us ---
Subscribe to Talk Python on YouTube: youtube.com
Talk Python on Bluesky: @talkpython.fm at bsky.app
Talk Python on Mastodon: talkpython
Michael on Bluesky: @mkennedy.codes at bsky.app
Michael on Mastodon: mkennedy