API Versioning
Skill Purpose: API version management, backward compatibility strategies, and version deprecation procedures
Core Skill Pattern
Objective: Establish robust API versioning strategy with backward compatibility, clear version communication, and smooth migration paths.
Universal Pattern:
- •Define API versioning strategy and approach
- •Create version identification and routing mechanisms
- •Establish backward compatibility procedures
- •Set up deprecation and sunset policies
- •Create version migration and communication patterns
Key Decisions (Project-Specific):
- •Versioning approach (URL, header, or content negotiation)
- •Version format and numbering scheme
- •Backward compatibility duration and support level
- •Deprecation timeline and communication strategy
- •Migration assistance and documentation
Project-Specific Implementation Notes
Customize per project:
- •Versioning approach based on API complexity and client requirements
- •Support duration based on stability guarantees and SLA commitments
- •Migration strategy based on client impact and resources
- •Communication approach based on stakeholder needs
- •Documentation depth based on version complexity
Example Implementation (URI Versioning Pattern)
Note: This is an example pattern using URI-based versioning. Adapt versioning approach and implementation based on your specific API requirements and client needs.
Prerequisites (Example)
- •API endpoints established and documented
- •Client integration patterns identified
- •Versioning requirements and constraints defined
- •Backward compatibility needs assessed
Example: API Versioning Implementation
Framework-Specific Example: This demonstrates URI-based versioning with Next.js. Adapt for your versioning approach and framework requirements.
Version Structure
typescript
// lib/api-version.ts
export const API_VERSIONS = {
V1: 'v1',
V2: 'v2',
CURRENT: 'v2',
SUPPORTED: ['v1', 'v2'],
DEPRECATED: [],
} as const;
export type ApiVersion = typeof API_VERSIONS[keyof typeof API_VERSIONS];
Version Middleware
typescript
// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
import { API_VERSIONS } from './lib/api-version';
export function middleware(request: NextRequest) {
const url = request.nextUrl;
// Extract version from URL path
const pathSegments = url.pathname.split('/');
const versionSegment = pathSegments[1];
// Validate version
if (versionSegment.startsWith('v') && !API_VERSIONS.SUPPORTED.includes(versionSegment as any)) {
return NextResponse.json(
{ error: 'Unsupported API version', supported: API_VERSIONS.SUPPORTED },
{ status: 400 }
);
}
// Add version headers
const response = NextResponse.next();
response.headers.set('API-Version', API_VERSIONS.CURRENT);
response.headers.set('API-Supported-Versions', API_VERSIONS.SUPPORTED.join(','));
return response;
}
export const config = {
matcher: ['/api/:path*'],
};
Versioned Route Structure
typescript
// app/api/v1/users/route.ts
import { NextResponse } from 'next/server';
export async function GET(request: NextRequest) {
// V1 implementation
const users = [
{ id: 1, name: 'John Doe', email: 'john@example.com' }
];
return NextResponse.json({ data: users });
}
export async function POST(request: NextRequest) {
const body = await request.json();
// V1 validation and creation logic
const user = {
id: Date.now(),
name: body.name,
email: body.email,
};
return NextResponse.json({ data: user }, { status: 201 });
}
typescript
// app/api/v2/users/route.ts
import { NextResponse } from 'next/server';
export async function GET(request: NextRequest) {
// V2 implementation with enhanced features
const users = [
{
id: 1,
name: 'John Doe',
email: 'john@example.com',
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString()
}
];
return NextResponse.json({
data: users,
meta: {
total: users.length,
version: 'v2'
}
});
}
export async function POST(request: NextRequest) {
const body = await request.json();
// V2 validation and creation with additional fields
const user = {
id: Date.now(),
name: body.name,
email: body.email,
role: body.role || 'user',
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
};
return NextResponse.json({
data: user,
meta: {
version: 'v2'
}
}, { status: 201 });
}
Version Compatibility Layer
typescript
// lib/version-compatibility.ts
export class VersionCompatibility {
static transformV1ToV2(v1Data: any): any {
// Transform V1 format to V2 format
return {
...v1Data,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
};
}
static transformV2ToV1(v2Data: any): any {
// Transform V2 format to V1 format
const { createdAt, updatedAt, ...v1Data } = v2Data;
return v1Data;
}
}
Deprecation Headers
typescript
// lib/deprecation-headers.ts
export function setDeprecationHeaders(response: NextResponse, version: string) {
if (version === 'v1') {
response.headers.set('Deprecation', 'true');
response.headers.set('Sunset', '2024-12-31'); // Sunset date
response.headers.set('Link', '</api/v2/users>; rel="successor-version"');
}
}
Version Documentation
typescript
// app/api/versions/route.ts
import { NextResponse } from 'next/server';
import { API_VERSIONS } from '../../../lib/api-version';
export async function GET() {
return NextResponse.json({
current: API_VERSIONS.CURRENT,
supported: API_VERSIONS.SUPPORTED,
deprecated: API_VERSIONS.DEPRECATED,
migration: {
v1_to_v2: {
guide: '/docs/migration/v1-to-v2',
breaking_changes: [
'Added createdAt and updatedAt fields',
'Response structure includes meta object',
'POST requests now accept optional role field'
],
sunset_date: '2024-12-31'
}
}
});
}
Best Practices
- •Semantic versioning - Use clear version numbers that communicate compatibility
- •Backward compatibility - Maintain support for existing clients during transition periods
- •Clear communication - Provide advance notice of deprecations and breaking changes
- •Migration assistance - Offer guides and tools to help clients upgrade
- •Version sunset - Define clear timelines for removing old versions
Stop Conditions
STOP and escalate if:
- •Versioning strategy unclear or conflicting
- •Backward compatibility requirements undefined
- •Migration impact not assessed
- •Client communication strategy missing
Skill Version: 1.0.0