Custom Header
title: "Custom Header Versioning — X-API-Version and Other Custom Headers" description: "Custom header versioning uses proprietary HTTP headers like X-API-Version to specify the version, offering flexibility but creating coupling to your API." date: 2026-06-28 lastmod: 2026-06-28 weight: 17 tags: [apis, versioning] }
Custom header versioning uses proprietary headers (X-API-Version, API-Version) to carry the version identifier, decoupling versioning from resource URLs.
What You'll Learn
- Custom header implementation
- Pros and cons of custom headers
- Comparison with standard headers
Why It Matters
Custom headers give you complete control over version behavior but create a non-standard dependency. Clients must know about your header.
Code Examples
# Custom header versioning
@app.route('/api/users')
def get_users():
version = request.headers.get('X-API-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
# Version header as a decorator
def versioned(min_version='1', max_version='2'):
def decorator(f):
@wraps(f)
def wrapper(*args, **kwargs):
version = request.headers.get('X-API-Version', '1')
if version < min_version or version > max_version:
return jsonify({"error": "Version not supported"}), 400
kwargs['api_version'] = version
return f(*args, **kwargs)
return wrapper
return decorator
@app.route('/api/products')
@versioned(min_version='1', max_version='2')
def get_products(api_version):
if api_version == '1':
return jsonify([p.basic() for p in products])
return jsonify([p.detail() for p in products])
// Express custom header versioning
app.get('/api/users', (req, res) => {
const version = req.headers['x-api-version'] || '1';
res.set('X-API-Version', version);
switch(version) {
case '1':
return res.json(users.map(u => ({ id: u.id, name: u.name })));
case '2':
return res.json(users.map(u => ({ id: u.id, name: u.name, email: u.email })));
default:
return res.status(400).json({ error: 'Unsupported version' });
}
});
// Middleware pattern
function versionMiddleware(req, res, next) {
req.apiVersion = req.headers['x-api-version'] || '1';
res.set('X-API-Version', req.apiVersion);
next();
}
app.use('/api', versionMiddleware);
Common Mistakes
1. Non-Standard Header Prefix
X-API-Version is fine, but avoid overly long or confusing names.
2. No Documentation of Header
Custom headers require explicit documentation for client developers.
3. Headers Stripped by Proxies
Some CDNs and proxies strip unknown headers.
4. Not Returning Version in Response
Always echo the version back so clients know what they got.
5. Case Sensitivity Issues
Header names are case-insensitive per HTTP spec. Parse accordingly.
Practice Questions
- What is a custom version header example?
- What is the advantage of custom headers?
- What is the main disadvantage?
- Why return X-API-Version in the response?
- How do proxies affect custom headers?
Answers:
- X-API-Version: 2.
- Clean URLs and direct control over versioning behavior.
- Non-standard, requiring documentation and potentially stripped by proxies.
- So clients can log and verify which version they received.
- Proxies and CDNs may strip unknown headers.
Challenge: Implement custom header versioning with middleware and test with curl. Show that the version is echoed in the response.
FAQ
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro