Versioning Project
DodaTech
2 min read
title: "API Versioning Project — Build a Versioned API System" description: "Build a complete versioned API system supporting multiple versions with routing, deprecation headers, migration guides, and automated compatibility testing." date: 2026-06-28 lastmod: 2026-06-28 weight: 31 tags: [apis, versioning] }
Build a production-ready versioned API system with multi-version routing, deprecation headers, migration documentation, and automated version compatibility testing.
What You'll Learn
- Implementing multi-version support
- Deprecation header management
- Version testing and validation
Why It Matters
This project combines all versioning concepts into a deployable API with proper version management, deprecation policies, and migration support.
Project Structure
# app.py - Versioned API
from flask import Flask, request, jsonify, Blueprint
from datetime import datetime, timedelta
import json
app = Flask(__name__)
# Version configuration
VERSIONS = {
'1': {'status': 'deprecated', 'sunset': '2026-12-31'},
'2': {'status': 'supported', 'sunset': None},
'3': {'status': 'latest', 'sunset': None},
}
# Version blueprints
v1 = Blueprint('v1', __name__)
v2 = Blueprint('v2', __name__)
v3 = Blueprint('v3', __name__)
# v1 - deprecated
@v1.route('/users')
def list_users_v1():
resp = jsonify([{"id": u.id, "name": u.name} for u in users])
return add_version_headers(resp, '1')
# v2 - current
@v2.route('/users')
def list_users_v2():
resp = jsonify([{"id": u.id, "name": u.name, "email": u.email} for u in users])
return add_version_headers(resp, '2')
# v3 - latest with cursor pagination
@v3.route('/users')
def list_users_v3():
cursor = request.args.get('cursor')
limit = min(request.args.get('limit', 20, type=int), 100)
# Cursor-based pagination
users_data = get_users_paginated(cursor, limit)
resp = jsonify({
"data": [{"id": u.id, "name": u.name, "email": u.email} for u in users_data],
"pagination": {"next_cursor": get_next_cursor(users_data, limit)}
})
return add_version_headers(resp, '3')
def add_version_headers(response, version):
info = VERSIONS[version]
response.headers['X-API-Version'] = version
if info['status'] == 'deprecated':
sunset = datetime.strptime(info['sunset'], '%Y-%m-%d')
response.headers['Deprecation'] = 'true'
response.headers['Sunset'] = sunset.strftime('%a, %d %b %Y %H:%M:%S GMT')
response.headers['Link'] = '</v3/users>; rel="successor-version"'
return response
# Register blueprints
app.register_blueprint(v1, url_prefix='/v1')
app.register_blueprint(v2, url_prefix='/v2')
app.register_blueprint(v3, url_prefix='/v3')
Testing
# test_versioning.py
def test_version_routing():
client = app.test_client()
# Test v1 (deprecated)
resp = client.get('/v1/users')
assert resp.status_code == 200
assert resp.headers['X-API-Version'] == '1'
assert resp.headers['Deprecation'] == 'true'
assert 'Sunset' in resp.headers
assert 'Link' in resp.headers
# Test v3 (latest)
resp = client.get('/v3/users')
assert resp.status_code == 200
assert resp.headers['X-API-Version'] == '3'
assert 'Deprecation' not in resp.headers
# Test unsupported version
resp = client.get('/v4/users')
assert resp.status_code == 404
def test_version_content():
client = app.test_client()
# v1 returns basic fields
v1_resp = client.get('/v1/users')
assert 'email' not in v1_resp.json[0]
# v3 returns email
v3_resp = client.get('/v3/users')
assert 'email' in v3_resp.json['data'][0]
Challenge
Extend the project with:
- Content negotiation versioning support
- CI/CD breaking change detection
- Version usage analytics dashboard
- Automated migration guide generation from changelog
FAQ
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro