| name | manage-api-versions |
| description | Manage API versions with proper migration strategies |
| shortcut | apiv |
Manage API Versions
Implement comprehensive API versioning strategies with backward compatibility, smooth migration paths, deprecation workflows, and automated compatibility testing to ensure seamless API evolution.
When to Use This Command
Use /manage-api-versions when you need to:
- Introduce breaking changes without disrupting existing clients
- Support multiple API versions simultaneously
- Provide smooth migration paths for API consumers
- Implement deprecation strategies with clear timelines
- Maintain backward compatibility while innovating
- Comply with enterprise SLA requirements
DON'T use this when:
- Building internal-only APIs with controlled clients (coordinate directly)
- API is in early beta with no production users (iterate freely)
- Changes are purely additive and backward compatible (versioning unnecessary)
Design Decisions
This command implements URL Path Versioning + Accept Header as the primary approach because:
- Most intuitive for developers (visible in URL)
- Easy to route and cache at infrastructure level
- Clear version separation in code organization
- Accept headers provide fine-grained control
- Works well with API gateways and CDNs
- Industry standard for REST APIs
Alternative considered: Header-Only Versioning
- Cleaner URLs
- More RESTful approach
- Harder to test and debug
- Recommended for purist REST APIs
Alternative considered: Query Parameter Versioning
- Easy to implement
- Optional versioning support
- Can pollute URL structure
- Recommended for simple versioning needs
Prerequisites
Before running this command:
- Define versioning strategy and policy
- Identify breaking vs. non-breaking changes
- Plan deprecation timeline (typically 6-12 months)
- Set up monitoring for version usage
- Prepare migration documentation
Implementation Process
Step 1: Choose Versioning Strategy
Select and implement the appropriate versioning mechanism for your API architecture.
Step 2: Create Version Infrastructure
Set up routing, middleware, and transformers for multi-version support.
Step 3: Implement Compatibility Layer
Build backward compatibility adapters and response transformers.
Step 4: Add Deprecation Workflow
Implement deprecation notices, sunset headers, and migration tools.
Step 5: Set Up Version Testing
Create comprehensive test suites covering all supported versions.
Output Format
The command generates:
api/v1/ - Version 1 implementation
api/v2/ - Version 2 implementation
middleware/version-router.js - Version routing logic
transformers/ - Version-specific data transformers
tests/compatibility/ - Cross-version compatibility tests
docs/migration-guide.md - Version migration documentation
Code Examples
Example 1: Comprehensive URL Path Versioning System
const express = require('express');
const semver = require('semver');
class APIVersionManager {
constructor(options = {}) {
this.versions = new Map();
this.defaultVersion = options.defaultVersion || 'v1';
this.deprecationPolicy = options.deprecationPolicy || {
warningPeriod: 90,
sunsetPeriod: 180
};
this.versionInfo = new Map();
}
registerVersion(version, router, metadata = {}) {
this.versions.set(version, router);
this.versionInfo.set(version, {
releaseDate: metadata.releaseDate || new Date(),
deprecatedDate: metadata.deprecatedDate,
sunsetDate: metadata.sunsetDate,
changes: metadata. || [],
: metadata. ||
});
}
() {
{
pathMatch = req..();
version = pathMatch ? : ;
acceptHeader = req.. || ;
headerMatch = acceptHeader.();
headerVersion = headerMatch ? : ;
requestedVersion = version || headerVersion || .;
(!..(requestedVersion)) {
res.().({
: ,
: ,
: .(..()),
: .()
});
}
versionMeta = ..(requestedVersion);
(versionMeta. === ) {
res.().({
: ,
: ,
: versionMeta.,
: .(),
:
});
}
res.({
: requestedVersion,
: requestedVersion
});
(versionMeta. === ) {
sunsetDate = versionMeta. || .(versionMeta.);
res.({
: ,
: sunsetDate.(),
: ,
:
});
res.(, {
.();
});
}
req. = requestedVersion;
req. = versionMeta;
versionRouter = ..(requestedVersion);
(req, res, next);
};
}
() {
versions = .(..());
versions.( semver.(a.(), b.()))[];
}
() {
.(..())
.( info. === )
.( version);
}
() {
sunset = (deprecatedDate);
sunset.(sunset.() + ..);
sunset;
}
() {
report = {
: .(),
: [],
: [],
: []
};
( [version, info] .) {
versionData = {
version,
: info.,
: info.
};
(info.) {
:
report..(versionData);
;
:
report..({
...versionData,
: info.
});
;
:
report..({
...versionData,
: info.
});
;
}
}
report;
}
}
v1Router = express.();
v1Router.(, (req, res) => {
users = ();
res.({
: users.( ({
: user.,
: user.,
: user.
}))
});
});
v1Router.(, (req, res) => {
user = (req..);
res.({
: {
: user.,
: user.,
: user.
}
});
});
v2Router = express.();
v2Router.(, (req, res) => {
users = ();
res.({
: users.( ({
: user.,
: user.,
: user.,
: {
: user.,
: user.,
: user.
}
})),
: {
: users.,
:
}
});
});
{
() {
(.(v2Response.)) {
{
: v2Response..( ({
: user.,
: user.,
: user.
}))
};
}
{
: {
: v2Response..,
: v2Response..,
: v2Response..
}
};
}
() {
{
...v1Request,
: v1Request.,
: {
: ,
: ,
: ().()
}
};
}
}
versionManager = ({
: ,
: {
: ,
:
}
});
versionManager.(, v1Router, {
: (),
: (),
: ,
: []
});
versionManager.(, v2Router, {
: (),
: ,
: [
,
,
]
});
app.(, versionManager.());
app.(, {
res.(versionManager.());
});
Example 2: Advanced Content Negotiation Versioning
const accepts = require('accepts');
class ContentNegotiationVersioning {
constructor() {
this.handlers = new Map();
this.transformers = new Map();
}
register(version, mediaType, handler, transformer = null) {
const key = `${version}:${mediaType}`;
this.handlers.set(key, handler);
if (transformer) {
this.transformers.set(key, transformer);
}
}
negotiate() {
return async (req, res, next) => {
const accept = accepts(req);
const supportedTypes = [
'application/vnd.api.v3+json',
'application/vnd.api.v2+json',
'application/vnd.api.v1+json',
'application/json'
];
const acceptedType = accept.type(supportedTypes);
if (!acceptedType) {
res.().({
: ,
: ,
: supportedTypes
});
}
version = ;
format = ;
versionMatch = acceptedType.();
(versionMatch) {
version = ;
}
formatMatch = acceptedType.();
(formatMatch) {
format = formatMatch[];
}
req. = version;
req. = format;
originalJson = res..(res);
res. = () {
transformerKey = ;
transformer = ..(transformerKey);
(transformer) {
data = (data, req);
}
res.(acceptedType);
res.({
: acceptedType,
: version,
:
});
(data);
}.();
();
};
}
}
{
() {
. = ();
. = ();
}
() {
key = ;
(!..(key)) {
..(key, []);
}
..(key).(change);
}
() {
key = ;
..(key, strategy);
}
() {
key = ;
changes = ..(key) || [];
issues = [];
( change changes) {
(change.(data)) {
issues.({
: change.,
: change.,
: change.,
: change.,
: change.
});
}
}
{
: issues. === ,
issues,
: issues.( i. !== )
};
}
() {
key = ;
strategy = ..(key);
(!strategy) {
();
}
(data);
}
}
compatibilityService = ();
compatibilityService.(, , {
: ,
: ,
: ,
: ,
: data.(),
: {
data. = data.;
data.;
data;
}
});
compatibilityService.(, , {
: ,
: ,
: ,
: ,
: !data.(),
: {
data. = {
: ,
: ,
: ().()
};
data;
}
});
compatibilityService.(, , {
migrated = { ...data };
(migrated.) {
migrated. = migrated.;
migrated.;
}
(!migrated.) {
migrated. = {
: ,
: ,
: ().()
};
}
(migrated. && .(migrated.)) {
migrated. = migrated..( ({
: addr. || ,
: addr,
: addr. ||
}));
migrated.;
}
migrated;
});
Example 3: Automated Version Testing and Documentation
const request = require('supertest');
const app = require('../app');
class VersionCompatibilityTester {
constructor(app) {
this.app = app;
this.versions = ['v1', 'v2', 'v3'];
this.endpoints = [];
this.results = [];
}
addEndpoint(method, path, testCases) {
this.endpoints.push({ method, path, testCases });
}
async runCompatibilityTests() {
console.log('Running API version compatibility tests...\n');
for (const endpoint of this.endpoints) {
for (const version of this.versions) {
for (const testCase of endpoint.testCases) {
const result = await this.(
version,
endpoint.,
endpoint.,
testCase
);
..(result);
status = result. ? : ;
.(
);
}
}
}
.();
}
() {
url = ;
{
response = (.)
[method.()](url)
.(testCase. || {})
.(, )
.(testCase. || );
validation = .(
version,
response.,
testCase.
);
{
version,
: ,
: testCase.,
: validation.,
: validation.,
: response.
};
} (error) {
{
version,
: ,
: testCase.,
: ,
: [error.],
:
};
}
}
() {
errors = [];
( field expectedSchema. || []) {
(!response.(field)) {
errors.();
}
}
( [field, type] .(expectedSchema. || {})) {
(response[field] !== && response[field] !== type) {
errors.();
}
}
{
: errors. === ,
errors
};
}
() {
report = {
: ().(),
: {
: ..,
: ..( r.).,
: ..( !r.).
},
: .(),
: ..( !r.),
: .()
};
().(
,
.(report, , )
);
report;
}
() {
matrix = {};
( version .) {
matrix[version] = {
: {},
:
};
( endpoint .) {
key = ;
results = ..(
r. === version && r. === key
);
matrix[version].[key] = {
: results.,
: results.( r.).
};
}
versionResults = ..( r. === version);
matrix[version]. = (
(versionResults.( r.). / versionResults.) *
).();
}
matrix;
}
() {
recommendations = [];
failurePatterns = {};
( failure ..( !r.)) {
key = failure.;
(!failurePatterns[key]) {
failurePatterns[key] = ();
}
failurePatterns[key].(failure.);
}
( [endpoint, versions] .(failurePatterns)) {
(versions. > ) {
recommendations.({
: ,
endpoint,
: .(versions),
:
});
}
}
recommendations;
}
}
tester = (app);
tester.(, , [
{
: ,
: ,
: {
: [],
: {
:
}
}
}
]);
tester.(, , [
{
: ,
: {
: ,
:
},
:
},
{
: ,
: {
: ,
: ,
: {
:
}
},
:
}
]);
tester.()
.( {
.();
.();
.();
.();
});
Error Handling
| Error | Cause | Solution |
|---|
| "Invalid API version" | Unsupported version requested | Return list of supported versions |
| "Version sunset" | Version no longer available | Provide migration guide and alternatives |
| "Incompatible request" | Breaking changes detected | Apply automatic migration if possible |
| "Deprecation warning ignored" | Client using deprecated version | Send stronger warnings, contact client |
| "Version routing conflict" | Overlapping route definitions | Review route precedence rules |
Configuration Options
Versioning Strategies
url-path: Version in URL path (/v1/)
header: Version in Accept header
query: Version in query parameter
subdomain: Version in subdomain (v1.api.example.com)
Deprecation Policies
aggressive: 3-month deprecation cycle
standard: 6-month deprecation cycle
conservative: 12-month deprecation cycle
enterprise: Custom per-client agreements
Best Practices
DO:
- Support at least 2 major versions simultaneously
- Provide clear deprecation timelines
- Version your database schemas
- Maintain comprehensive migration documentation
- Use semantic versioning
- Monitor version usage analytics
DON'T:
- Remove versions without notice
- Make breaking changes in minor versions
- Ignore backward compatibility
- Version too granularly
- Mix versioning strategies
Performance Considerations
- Cache responses per version
- Lazy-load version-specific code
- Use CDN with version-aware caching
- Monitor performance per version
- Optimize hot migration paths
Monitoring and Analytics
const versionMetrics = {
requests: new Map(),
deprecated: new Map(),
errors: new Map()
};
app.use((req, res, next) => {
const version = req.apiVersion || 'unknown';
versionMetrics.requests.set(
version,
(versionMetrics.requests.get(version) || 0) + 1
);
next();
});
Related Commands
/api-documentation-generator - Generate version-specific docs
/api-sdk-generator - Create versioned SDKs
/api-testing-framework - Test version compatibility
/api-migration-tool - Automate version migrations
Version History
- v1.0.0 (2024-10): Initial implementation with URL path versioning
- Planned v1.1.0: Add GraphQL schema versioning support