Header Versioning
title: "Header Versioning — Accept-Version and Custom Headers for API Versioning" description: "Header versioning uses HTTP request headers like Accept-Version or a custom header to specify the API version, keeping URLs clean and RESTful." date: 2026-06-28 lastmod: 2026-06-28 weight: 14 tags: [apis, versioning] }
Header versioning uses HTTP headers (Accept-Version, X-API-Version) to communicate the desired API version, keeping resource URLs unchanged across versions.
What You'll Learn
- Accept-Version header
- Custom version headers
- Header versioning tradeoffs
Why It Matters
Header versioning keeps URLs clean and RESTful. The same URL serves different versions based on the header, which is useful for caching.
Code Examples
# Accept-Version header versioning
@app.route('/api/users')
def get_users():
version = request.headers.get('Accept-Version', '1')
if version == '1':
data = [{"id": u.id, "name": u.name} for u in users]
elif version == '2':
data = [{"id": u.id, "name": u.name, "email": u.email} for u in users]
else:
return jsonify({"error": "Unsupported version"}), 400
response = jsonify(data)
response.headers['X-API-Version'] = version
return response
# Custom header versioning
@app.route('/api/products')
def get_products():
version = request.headers.get('X-API-Version', '1')
if version == '1':
return jsonify([p.to_dict_v1() for p in products])
elif version == '2':
return jsonify([p.to_dict_v2() for p in products])
// Express header versioning
app.get('/api/users', (req, res) => {
const version = req.headers['accept-version'] || '1';
const handlers = {
'1': () => res.json(users.map(u => ({ id: u.id, name: u.name }))),
'2': () => res.json(users.map(u => ({ id: u.id, name: u.name, email: u.email })))
};
const handler = handlers[version];
if (!handler) return res.status(400).json({ error: 'Unsupported version' });
res.set('X-API-Version', version);
handler();
});
# Middleware-based header versioning
class VersionMiddleware:
def __init__(self, app):
self.app = app
def __call__(self, environ, start_response):
version = environ.get('HTTP_ACCEPT_VERSION', '1')
environ['api.version'] = version
return self.app(environ, start_response)
# Use middleware
app.wsgi_app = VersionMiddleware(app.wsgi_app)
Common Mistakes
1. No Default Version
Without Accept-Version, default to the latest version.
2. Not Returning Version in Response
Include X-API-Version so clients know which version they received.
3. Headers Not Forwarded by Proxies
Proxies may strip custom headers. Use standard Accept header.
4. Harder to Test and Document
URL-based versions are easier to test in browsers and tools.
5. No Version in Error Responses
Include supported versions in error responses.
Practice Questions
- What header is commonly used for versioning?
- What is the advantage of header versioning?
- What is the disadvantage?
- Why return version in response headers?
- How do proxies affect header versioning?
Answers:
- Accept-Version or X-API-Version.
- Clean URLs that don't change with versions.
- Harder to test, document, and discover.
- So clients know which version they received and can log it.
- Proxies may strip custom headers; use Accept-Version which is more standard.
Challenge: Implement header versioning with middleware. Create a test that sends different Accept-Version headers and verifies correct version responses.
FAQ
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro