API Versioning & Router Composition
Part of: Advanced FastAPI Patterns
Learn to version your API using APIRouter with prefixes and tags, composing multiple versioned routers into a single application.
What You'll Learn
- Understand different API versioning strategies and when to use URL-based versioning
- Create separate APIRouter instances for each API version
- Use prefix and tags parameters to organize versioned routes
- Compose multiple routers into a single FastAPI application with include_router
Theory and Concepts
API Versioning & Router Composition
🎯 What You'll Learn
- Different strategies for versioning APIs (URL, header, query parameter)
- How to use APIRouter with prefix and tags for modular route organization
- How to compose multiple routers into a single FastAPI application
- Best practices for backward compatibility and deprecation
📚 Theory
As your API evolves, you will inevitably need to make breaking changes -- changing response formats, renaming fields, or restructuring endpoints. API versioning allows you to introduce these changes without breaking existing clients. FastAPI's APIRouter makes it straightforward to implement URL-based versioning by composing multiple versioned routers into a single application.
Why Version Your API?
Without versioning, any change to your response format or endpoint behavior breaks all existing clients. Versioning lets you:
- Introduce breaking changes safely alongside the old version
- Give clients time to migrate to the new version
- Maintain multiple versions simultaneously during transition periods
- Deprecate old versions on a published schedule
Versioning Strategies
There are three common approaches to API versioning:
1. URL Path Versioning (Recommended for most cases)
The version is part of the URL path. This is the most visible and explicit approach.
[Code Example]
Advantages: Easy to understand, cache-friendly, simple to route.
Disadvantages: URL changes between versions, requires client URL updates.
2. Header-Based Versioning
The version is specified in a custom request header.
[Code Example]
Advantages: Clean URLs, version is metadata not resource identity.
Disadvantages: Harder to test in browser, less discoverable.
3. Query Parameter Versioning
The version is a query parameter.
[Code Example]
Advantages: Easy to test, no URL or header changes needed.
Disadvantages: Can conflict with other parameters, less semantic.
APIRouter: The Building Block
APIRouter works like a mini-FastAPI application. It can have its own endpoints, dependencies, and middleware. The key parameters for versioning are prefix and tags.
[Code Example]
The prefix parameter prepends a path to all routes on the router. The tags parameter groups endpoints in the OpenAPI documentation.
Composing Routers with include_router
Once you have defined your versioned routers, include them in the main application:
[Code Example]
include_router also accepts optional prefix, tags, and deprecated parameters that can override or extend the router's settings at include time.
Evolving Response Formats
A common pattern is to have v1 return simple data and v2 return enriched, paginated responses:
[Code Example]
The v2 format adds a data wrapper, item count, and version identifier. This pattern scales well as you add pagination, filtering metadata, or hypermedia links.
Backward Compatibility
When evolving your API, follow these guidelines:
- Additive changes are safe: Adding new fields to responses does not break clients
- Removing fields is breaking: Always version when removing response fields
- Changing field types is breaking: Changing a field from string to integer requires a new version
- New optional parameters are safe: Adding optional query or body parameters is backward-compatible
Deprecation Strategy
When retiring an old API version, follow these steps: announce the timeline to clients, mark routes as deprecated using deprecated=True in include_router, add deprecation headers to responses, monitor usage, and finally remove the old version after the deadline.
[Code Example]
🔧 Key Concepts
- API Versioning: Managing multiple versions of your API simultaneously
- URL Path Versioning: Embedding the version in the URL (e.g., /api/v1/)
- APIRouter: A modular routing component with its own prefix, tags, and dependencies
- prefix: Path prefix prepended to all routes on a router
- tags: Labels that group endpoints in OpenAPI documentation
- include_router: Method that mounts a router onto the main application
- Backward Compatibility: Ensuring existing clients continue to work with API changes
- Deprecation: The process of phasing out an old API version
💡 Best Practices
- Use URL path versioning for public APIs -- it is the most explicit and discoverable approach
- Extract shared business logic into service functions to avoid code duplication between versions
- Only create a new version when you have a genuinely breaking change
- Mark deprecated versions clearly in your OpenAPI documentation
- Give clients a reasonable migration window (typically 6-12 months) before removing old versions
- Include a version identifier in enriched responses so clients can verify they are hitting the right version
- Use tags consistently to organize endpoints in the auto-generated docs
🔗 Additional Resources
- FastAPI Bigger Applications Docs
- FastAPI APIRouter Reference
- API Versioning Best Practices
Helpful Hint
Create separate APIRouter instances with prefix='/api/v1' and prefix='/api/v2'. Define your endpoints on the routers, then call app.include_router() for each one. The v2 router should return richer response objects with 'data', 'total', and 'version' fields.
