API versioning helps keep your app working well when you add new features or change things. It lets old and new users use the API without problems.
API versioning strategies in FastAPI
from fastapi import FastAPI app = FastAPI() @app.get("/v1/items") async def get_items_v1(): return {"version": "v1", "items": ["apple", "banana"]} @app.get("/v2/items") async def get_items_v2(): return {"version": "v2", "items": [{"name": "apple"}, {"name": "banana"}]}
Versioning can be done in the URL path, query parameters, or headers.
URL path versioning is the simplest and most common method.
from fastapi import FastAPI app = FastAPI() @app.get("/v1/users") async def users_v1(): return {"version": "v1", "users": ["Alice", "Bob"]}
from fastapi import FastAPI, Header, HTTPException app = FastAPI() @app.get("/users") async def users(x_api_version: str | None = Header(default="1")): if x_api_version == "1": return {"version": "v1", "users": ["Alice", "Bob"]} elif x_api_version == "2": return {"version": "v2", "users": [{"name": "Alice"}, {"name": "Bob"}]} else: raise HTTPException(status_code=400, detail="Unsupported API version")
from fastapi import FastAPI, Query app = FastAPI() @app.get("/users") async def users(api_version: str = Query("1")): if api_version == "1": return {"version": "v1", "users": ["Alice", "Bob"]} elif api_version == "2": return {"version": "v2", "users": [{"name": "Alice"}, {"name": "Bob"}]} else: return {"error": "Unsupported API version"}
This FastAPI app uses a custom header 'X-API-Version' to decide which version of the items list to return. If the header is '1', it returns a simple list. If '2', it returns a list of objects. If the version is unsupported, it returns an error.
from fastapi import FastAPI, Header, HTTPException app = FastAPI() @app.get("/items") async def read_items(x_api_version: str | None = Header(default="1")): if x_api_version == "1": return {"version": "v1", "items": ["apple", "banana"]} elif x_api_version == "2": return {"version": "v2", "items": [{"name": "apple"}, {"name": "banana"}]} else: raise HTTPException(status_code=400, detail="Unsupported API version")
Using URL path versioning is easy to understand and test.
Header or query parameter versioning keeps URLs clean but needs clients to send extra info.
Always document your API versions clearly for users.
API versioning helps keep old and new API users happy.
Common ways: URL path, headers, or query parameters.
Choose the method that fits your app and users best.
Practice
Solution
Step 1: Understand API versioning concept
API versioning lets you keep old and new API versions available so different clients can use the version they need.Step 2: Identify the main goal
The main goal is to support multiple API versions simultaneously without breaking existing clients.Final Answer:
To allow multiple versions of an API to coexist and support different clients -> Option CQuick Check:
API versioning = support multiple versions [OK]
- Thinking versioning speeds up API
- Confusing versioning with security encryption
- Assuming versioning auto-generates docs
Solution
Step 1: Check route path syntax
FastAPI routes must start with a slash '/' to be valid paths.Step 2: Identify correct version prefix
Versioning by URL path usually prefixes the version like '/v1/' before the resource path.Final Answer:
app.get('/v1/items/') -> Option BQuick Check:
Versioned route starts with '/' and version prefix [OK]
- Omitting leading slash in route path
- Placing version after resource path incorrectly
- Using quotes without leading slash
/api/items with header X-API-Version: 2?
from fastapi import FastAPI, Header, HTTPException
app = FastAPI()
@app.get('/api/items')
async def get_items(x_api_version: str | None = Header(None)):
if x_api_version == '1':
return {'version': 1, 'items': ['apple', 'banana']}
elif x_api_version == '2':
return {'version': 2, 'items': ['orange', 'grape']}
else:
raise HTTPException(status_code=400, detail='Unsupported API version')Solution
Step 1: Check header value handling
The function reads the header 'X-API-Version' and compares it to '1' or '2'.Step 2: Match header '2' to response
Since header is '2', it returns the dictionary with version 2 and items ['orange', 'grape'].Final Answer:
{'version': 2, 'items': ['orange', 'grape']} -> Option DQuick Check:
Header 'X-API-Version: 2' returns version 2 data [OK]
- Ignoring header and returning default
- Confusing version 1 and 2 outputs
- Assuming 404 error instead of 400
from fastapi import FastAPI
app = FastAPI()
@app.get('/items')
async def read_items(version: int = 1):
if version == 1:
return {'items': ['pen', 'notebook']}
elif version == 2:
return {'items': ['pencil', 'eraser']}
else:
return {'error': 'Unsupported version'}Solution
Step 1: Check error handling for unsupported versions
Returning a dict with 'error' key is not standard; better to raise HTTPException with status code.Step 2: Understand FastAPI error response best practice
Raising HTTPException sends proper HTTP error status and message to client.Final Answer:
The function should raise HTTPException for unsupported versions instead of returning dict -> Option AQuick Check:
Use HTTPException for errors, not plain dict [OK]
- Returning error dict instead of raising exception
- Thinking query parameter must use Query() always
- Assuming version must be in URL path
/v1/users, and version 2 uses header versioning with X-API-Version: 2 on the same /users path. How can you implement this correctly?Solution
Step 1: Separate version 1 and version 2 routes
Version 1 uses URL path '/v1/users', so define a route with that path.Step 2: Define version 2 route with header check
Version 2 uses header on '/users', so define a route '/users' that reads 'X-API-Version' header to confirm version 2.Final Answer:
Create two separate routes: one with path '/v1/users' for version 1, and one with path '/users' that checks header 'X-API-Version' for version 2 -> Option AQuick Check:
Separate routes for different versioning methods [OK]
- Mixing path and header versioning in one route
- Using only header or only path for both versions
- Trying to detect path version inside header route
Ready to prove it?
Pass the test and this pattern moves unknown
