Version Management Strategies

API versioning is like having different editions of a software library. Each version represents a snapshot of the API at a specific point in time, with its own set of features, bug fixes, and behaviors. Unlike traditional software where you choose which version to install, with APIs you specify which “edition” you want to use with each request.

How API Versioning Works

Think of API versioning like a library with multiple editions of the same book:

  1. Version Selection: You specify which edition (version) you want to read with each request
  2. Compatibility: Each version maintains its behavior, even as newer versions are released
  3. Deprecation: Older editions eventually go out of print (get deprecated)
  4. Sunset: Eventually, very old editions are removed from the library entirely

The API uses your version header to determine which set of behaviors, response formats, and business logic to apply to your request.

Version Lifecycle Management

Every API version goes through a predictable lifecycle:

  • Active: Current version, fully supported with new features
  • Deprecated: Still works but marked for future removal
  • Sunset: No longer available, returns 410 Gone

Understanding Deprecation Headers

When you use a deprecated API version, the response includes detailed information about the deprecation timeline:

Response Headers

Deprecation
RFC 8594 standard header indicating when the version was officially deprecated.

Deprecation: Wed, 11 Nov 2024 23:59:59 GMT

Sunset
RFC 8594 standard header indicating when the version will stop working.

Sunset: Wed, 11 Nov 2025 23:59:59 GMT

X-Fanvue-API-Next-Version
Fanvue-specific header recommending which version to migrate to.

X-Fanvue-API-Next-Version: 2025-06-26

Example Response with Deprecation

Here’s what you’ll see when using a deprecated version:

1HTTP/1.1 200 OK
2Deprecation: Wed, 11 Nov 2024 23:59:59 GMT
3Sunset: Wed, 11 Nov 2025 23:59:59 GMT
4X-Fanvue-API-Next-Version: 2025-06-26
5Content-Type: application/json
6
7{
8 "uuid": "123e4567-e89b-12d3-a456-426614174000",
9 "email": "user@example.com",
10 "handle": "creator123"
11}

This response tells you:

  • The version was deprecated on November 11, 2024
  • It will stop working on November 11, 2025
  • You should migrate to version 2025-06-26
  • Your request still works for now

Version Error Responses

Unsupported Version (400)

When you request a version that was never supported:

1HTTP/1.1 400 Bad Request
2Content-Type: application/json
3
4{
5 "error": "Unsupported API version",
6 "message": "API version '2024-01-01' is not supported"
7}

Sunset Version (410)

When you request a version that has been permanently removed:

1HTTP/1.1 410 Gone
2Content-Type: application/json
3
4{
5 "error": "API version no longer supported",
6 "message": "API version '2024-01-01' was sunset on 2024-12-31T00:00:00.000Z",
7 "nextVersion": "2025-06-26"
8}

Building Version-Aware Applications

Version Header Management

Always include the version header in your API client configuration:

1class FanvueAPIClient {
2 constructor(apiKey, version) {
3 this.apiKey = apiKey;
4 this.version = version;
5 this.baseURL = "https://api.fanvue.com";
6 }
7
8 async request(endpoint, options = {}) {
9 const response = await fetch(`${this.baseURL}${endpoint}`, {
10 ...options,
11 headers: {
12 "X-Fanvue-API-Key": this.apiKey,
13 "X-Fanvue-API-Version": this.version,
14 "Content-Type": "application/json",
15 ...options.headers,
16 },
17 });
18
19 // Check for deprecation warnings
20 this.handleDeprecationHeaders(response);
21
22 return this.handleResponse(response);
23 }
24
25 handleDeprecationHeaders(response) {
26 const deprecation = response.headers.get("Deprecation");
27 const sunset = response.headers.get("Sunset");
28 const nextVersion = response.headers.get("X-Fanvue-API-Next-Version");
29
30 if (deprecation) {
31 console.warn(`API version ${this.version} is deprecated as of ${deprecation}`);
32 if (sunset) {
33 console.warn(`Version will stop working on ${sunset}`);
34 }
35 if (nextVersion) {
36 console.warn(`Consider upgrading to version ${nextVersion}`);
37 }
38 }
39 }
40}

Version Error Handling

Implement robust error handling for version-related failures:

1async function handleResponse(response) {
2 if (response.status === 400) {
3 const error = await response.json();
4 if (error.error === "Unsupported API version") {
5 throw new UnsupportedVersionError(error.message);
6 }
7 }
8
9 if (response.status === 410) {
10 const error = await response.json();
11 if (error.error === "API version no longer supported") {
12 throw new SunsetVersionError(error.message, error.nextVersion);
13 }
14 }
15
16 if (!response.ok) {
17 throw new APIError(`HTTP ${response.status}: ${response.statusText}`);
18 }
19
20 return response.json();
21}
22
23class UnsupportedVersionError extends Error {
24 constructor(message) {
25 super(message);
26 this.name = "UnsupportedVersionError";
27 }
28}
29
30class SunsetVersionError extends Error {
31 constructor(message, nextVersion) {
32 super(message);
33 this.name = "SunsetVersionError";
34 this.nextVersion = nextVersion;
35 }
36}

Python Implementation

1import requests
2import logging
3from datetime import datetime
4from typing import Optional
5
6class FanvueClient:
7 def __init__(self, api_key: str, version: str):
8 self.api_key = api_key
9 self.version = version
10 self.base_url = "https://api.fanvue.com"
11 self.session = requests.Session()
12 self.session.headers.update({
13 'X-Fanvue-API-Key': api_key,
14 'X-Fanvue-API-Version': version,
15 'Content-Type': 'application/json'
16 })
17
18 def request(self, method: str, endpoint: str, **kwargs):
19 response = self.session.request(method, f"{self.base_url}{endpoint}", **kwargs)
20
21 # Monitor deprecation status
22 self._check_deprecation_headers(response)
23
24 # Handle version errors
25 if response.status_code == 400:
26 error_data = response.json()
27 if "Unsupported API version" in error_data.get("error", ""):
28 raise UnsupportedVersionError(error_data["message"])
29
30 if response.status_code == 410:
31 error_data = response.json()
32 if "API version no longer supported" in error_data.get("error", ""):
33 raise SunsetVersionError(
34 error_data["message"],
35 error_data.get("nextVersion")
36 )
37
38 response.raise_for_status()
39 return response.json()
40
41 def _check_deprecation_headers(self, response):
42 deprecation = response.headers.get('Deprecation')
43 sunset = response.headers.get('Sunset')
44 next_version = response.headers.get('X-Fanvue-API-Next-Version')
45
46 if deprecation:
47 logging.warning(f"API version {self.version} deprecated as of {deprecation}")
48 if sunset:
49 sunset_date = datetime.strptime(sunset, '%a, %d %b %Y %H:%M:%S %Z')
50 logging.warning(f"Version sunset scheduled for {sunset_date}")
51 if next_version:
52 logging.warning(f"Recommended migration to version {next_version}")
53
54class UnsupportedVersionError(Exception):
55 pass
56
57class SunsetVersionError(Exception):
58 def __init__(self, message: str, next_version: Optional[str] = None):
59 super().__init__(message)
60 self.next_version = next_version

Advanced Version Management Strategies

Version Pinning

Pin to specific versions in production to ensure predictable behavior:

1// Good: Explicit version pinning
2const client = new FanvueAPIClient(apiKey, "2025-06-26");
3
4// Avoid: Dynamic version selection in production
5const client = new FanvueAPIClient(apiKey, getLatestVersion());

Graceful Migration Patterns

Implement gradual migration with fallback logic:

1class VersionMigrationClient extends FanvueAPIClient {
2 constructor(apiKey, primaryVersion, fallbackVersion) {
3 super(apiKey, primaryVersion);
4 this.fallbackVersion = fallbackVersion;
5 }
6
7 async requestWithFallback(endpoint, options = {}) {
8 try {
9 return await this.request(endpoint, options);
10 } catch (error) {
11 if (error instanceof SunsetVersionError) {
12 console.warn(`Primary version sunset, falling back to ${this.fallbackVersion}`);
13 // Create temporary client with fallback version
14 const fallbackClient = new FanvueAPIClient(this.apiKey, this.fallbackVersion);
15 return await fallbackClient.request(endpoint, options);
16 }
17 throw error;
18 }
19 }
20}

Monitoring and Alerting

Set up monitoring for deprecation warnings:

1class MonitoredAPIClient extends FanvueAPIClient {
2 constructor(apiKey, version, metricsCollector) {
3 super(apiKey, version);
4 this.metrics = metricsCollector;
5 }
6
7 handleDeprecationHeaders(response) {
8 const deprecation = response.headers.get("Deprecation");
9 const sunset = response.headers.get("Sunset");
10
11 if (deprecation) {
12 this.metrics.increment("api.version.deprecated", {
13 version: this.version,
14 deprecation_date: deprecation,
15 sunset_date: sunset,
16 });
17
18 // Alert if sunset is approaching
19 if (sunset) {
20 const sunsetDate = new Date(sunset);
21 const daysUntilSunset = (sunsetDate - new Date()) / (1000 * 60 * 60 * 24);
22
23 if (daysUntilSunset <= 30) {
24 this.metrics.alert("api.version.sunset_approaching", {
25 version: this.version,
26 days_remaining: Math.floor(daysUntilSunset),
27 });
28 }
29 }
30 }
31 }
32}

Best Practices for Production

Configuration Management

  • Store API versions in environment variables or configuration files
  • Use the same version across all environments (dev, staging, production)
  • Document which version each deployment uses

Testing Strategy

  • Test version migration in staging environments first
  • Implement integration tests for each supported API version
  • Validate that deprecated versions still work as expected

Deployment Planning

  • Plan version migrations during maintenance windows
  • Implement feature flags for gradual version rollouts
  • Monitor error rates closely after version changes

Team Coordination

  • Establish clear policies for when to upgrade API versions
  • Create alerts for deprecation warnings in production
  • Document migration procedures for your team