api-versioning

API versioning strategies — URL path, header, query param, content negotiation — with breaking change classification, deprecation timelines, migration patterns, and multi-version support. Use when evolving APIs, planning breaking changes, or managing version lifecycles.

MIT-0 · Free to use, modify, and redistribute. No attribution required.
0 · 571 · 0 current installs · 0 all-time installs
MIT-0
Security Scan
VirusTotalVirusTotal
Benign
View report →
OpenClawOpenClaw
Benign
high confidence
Purpose & Capability
The name and description (API versioning strategies, deprecation, migration) match the SKILL.md content and README. No unexpected capabilities, binaries, or credentials are requested.
Instruction Scope
SKILL.md contains guidance, patterns, and code examples only; it does not instruct the agent to read system files, collect environment variables, or transmit data to external endpoints beyond illustrative snippets. Examples contain placeholders (e.g., [...]) that are clearly illustrative.
Install Mechanism
There is no formal install spec in the registry (instruction-only), which is lowest risk. The README includes an 'npx add' line pointing at a GitHub tree URL and several manual copy/installation examples referencing local ~/.ai-skills and .cursor paths; these are just user instructions, but the GitHub tree URL is an unusual form for 'npx' and may not behave as expected. This is not inherently malicious but worth verifying before executing any install commands.
Credentials
No environment variables, credentials, or config paths are requested. The guidance does not reference hidden secrets or unrelated service tokens.
Persistence & Privilege
Skill defaults (always:false, user-invocable:true, model invocation enabled) are standard and appropriate for an instruction-only skill. The skill does not request permanent presence or modify other skills/configurations.
Assessment
This skill appears to be a documentation/guide for API versioning and is internally consistent. Before installing or running any copy commands referenced in the README, inspect the SKILL.md and README locally (you already have them) and avoid running unknown install commands (e.g., 'npx' with an unfamiliar URL) without review. If you plan to use code snippets, treat them as examples — replace placeholders, review for correctness, and run in a safe environment. If you need higher assurance, confirm the skill's origin (owner) or host it from a trusted repository before executing any installation steps.

Like a lobster shell, security has layers — review code before you run it.

Current versionv1.0.0
Download zip
latestvk9776bfypvze2m6a48qywbwm6s80xjsw

License

MIT-0
Free to use, modify, and redistribute. No attribution required.

SKILL.md

API Versioning Patterns

Evolve your API confidently. Version correctly, deprecate gracefully, migrate safely — without breaking existing consumers.

Versioning Strategies

Pick one strategy and apply it consistently across your entire API surface.

StrategyFormatVisibilityCacheabilityBest For
URL Path/api/v1/usersHighExcellentPublic APIs, third-party integrations
Query Param/api/users?v=1MediumModerateSimple APIs, prototyping
HeaderAccept-Version: v1LowGoodInternal APIs, coordinated consumers
Content NegotiationAccept: application/vnd.api.v1+jsonLowGoodEnterprise, strict REST compliance

URL Path Versioning

The most common strategy. Version lives in the URL, making it immediately visible.

from fastapi import FastAPI, APIRouter

v1 = APIRouter(prefix="/api/v1")
v2 = APIRouter(prefix="/api/v2")

@v1.get("/users")
async def list_users_v1():
    return {"users": [...]}

@v2.get("/users")
async def list_users_v2():
    return {"data": {"users": [...]}, "meta": {...}}

app = FastAPI()
app.include_router(v1)
app.include_router(v2)

Rules:

  • Always prefix: /api/v1/... not /v1/api/...
  • Major version only: /api/v1/, never /api/v1.2/ or /api/v1.2.3/
  • Every endpoint must be versioned — no mixing versioned and unversioned paths

Header Versioning

Version specified via request headers, keeping URLs clean.

function versionRouter(req, res, next) {
  const version = req.headers['accept-version'] || 'v2'; // default to latest
  req.apiVersion = version;
  next();
}

app.get('/api/users', versionRouter, (req, res) => {
  if (req.apiVersion === 'v1') return res.json({ users: [...] });
  if (req.apiVersion === 'v2') return res.json({ data: { users: [...] }, meta: {} });
  return res.status(400).json({ error: `Unsupported version: ${req.apiVersion}` });
});

Always define fallback behavior when no version header is sent — default to latest stable or return 400 Bad Request.

Semantic Versioning for APIs

SemVer ComponentAPI MeaningAction Required
MAJOR (v1 → v2)Breaking changes — remove field, rename endpoint, change authClients must migrate
MINOR (v1.1 → v1.2)Additive, backward-compatible — new optional field, new endpointNo client changes
PATCH (v1.1.0 → v1.1.1)Bug fixes, no behavior changeNo client changes

Only MAJOR versions appear in URL paths. Communicate MINOR and PATCH through changelogs.


Breaking vs Non-Breaking Changes

Breaking — Require New Version

ChangeWhy It Breaks
Remove a response fieldClients reading that field get undefined
Rename a fieldSame as removal from the client's perspective
Change a field's type"id": 123"id": "123" breaks typed clients
Remove an endpointClients calling it get 404
Make optional param requiredExisting requests missing it start failing
Change URL structureBookmarked/hardcoded URLs break
Change error response formatClient error-handling logic breaks
Change authentication mechanismExisting credentials stop working

Non-Breaking — Safe Under Same Version

ChangeWhy It's Safe
Add new optional response fieldClients ignore unknown fields
Add new endpointDoesn't affect existing endpoints
Add new optional query/body paramExisting requests work without it
Add new enum valueSafe if clients handle unknown values gracefully
Relax a validation constraintPreviously valid requests remain valid
Improve performanceSame interface, faster response

Deprecation Strategy

Never remove a version without warning. Follow this timeline:

Phase 1: ANNOUNCE
  • Sunset header on responses  • Changelog entry
  • Email/webhook to consumers  • Docs marked "deprecated"

Phase 2: SUNSET PERIOD
  • v1 still works but warns     • Monitor v1 traffic
  • Contact remaining consumers  • Provide migration support

Phase 3: REMOVAL
  • v1 returns 410 Gone
  • Response body includes migration guide URL
  • Redirect docs to v2

Minimum deprecation periods: Public API: 12 months · Partner API: 6 months · Internal API: 1–3 months

Sunset HTTP Header (RFC 8594)

Include on every response from a deprecated version:

HTTP/1.1 200 OK
Sunset: Sat, 01 Mar 2025 00:00:00 GMT
Deprecation: true
Link: <https://api.example.com/docs/migrate-v1-v2>; rel="sunset"
X-API-Warn: "v1 is deprecated. Migrate to v2 by 2025-03-01."

Retired Version Response

When past sunset, return 410 Gone:

{
  "error": "VersionRetired",
  "message": "API v1 was retired on 2025-03-01.",
  "migration_guide": "https://api.example.com/docs/migrate-v1-v2",
  "current_version": "v2"
}

Migration Patterns

Adapter Pattern

Shared business logic, version-specific serialization:

class UserService:
    async def get_user(self, user_id: str) -> User:
        return await self.repo.find(user_id)

def to_v1(user: User) -> dict:
    return {"id": user.id, "name": user.full_name, "email": user.email}

def to_v2(user: User) -> dict:
    return {
        "id": user.id,
        "name": {"first": user.first_name, "last": user.last_name},
        "emails": [{"address": e, "primary": i == 0} for i, e in enumerate(user.emails)],
        "created_at": user.created_at.isoformat(),
    }

Facade Pattern

Single entry point delegates to the correct versioned handler:

async def get_user(user_id: str, version: int):
    user = await user_service.get_user(user_id)
    serializers = {1: to_v1, 2: to_v2}
    serialize = serializers.get(version)
    if not serialize:
        raise UnsupportedVersionError(version)
    return serialize(user)

Versioned Controllers

Separate controller files per version, shared service layer:

api/
  v1/
    users.py      # v1 request/response shapes
    orders.py
  v2/
    users.py      # v2 request/response shapes
    orders.py
  services/
    user_service.py   # version-agnostic business logic
    order_service.py

API Gateway Routing

Route versions at infrastructure layer:

routes:
  - match: /api/v1/*
    upstream: api-v1-service:8080
  - match: /api/v2/*
    upstream: api-v2-service:8080

Multi-Version Support

Architecture:

Request → API Gateway → Version Router → v1 Handler → Shared Service Layer → DB
                                        → v2 Handler ↗

Principles:

  1. Business logic is version-agnostic. Services, repositories, and domain models are shared.
  2. Serialization is version-specific. Each version has its own request validators and response serializers.
  3. Transformations are explicit. A v1_to_v2 transformer documents every field mapping.
  4. Tests cover all active versions. Every supported version has its own integration test suite.

Maximum concurrent versions: 2–3 active (current + 1–2 deprecated). More than 3 creates unsustainable maintenance burden.


Client Communication

Changelog

Publish a changelog for every release, tagged by version and change type:

## v2.3.0 — 2025-02-01
### Added
- `avatar_url` field on User response
- `GET /api/v2/users/{id}/activity` endpoint
### Deprecated
- `name` field on User — use `first_name` and `last_name` (removal in v3)

Migration Guides

For every major version bump, provide:

  • Field-by-field mapping table (v1 → v2)
  • Before/after request and response examples
  • Code snippets for common languages/SDKs
  • Timeline with key dates (announcement, sunset, removal)

SDK Versioning

Align SDK major versions with API major versions:

api-client@1.x  →  /api/v1
api-client@2.x  →  /api/v2

Ship the new SDK before announcing API deprecation.


Anti-Patterns

Anti-PatternFix
Versioning too frequentlyBatch breaking changes into infrequent major releases
Breaking without noticeAlways follow the deprecation timeline
Eternal version supportSet and enforce sunset dates
Inconsistent versioningOne version scheme, applied uniformly
Version per endpointVersion the entire API surface together
Using versions to gate featuresUse feature flags separately; versions are for contracts
No default versionAlways define a default or return explicit 400

NEVER Do

  1. NEVER remove a field, endpoint, or change a type without bumping the major version
  2. NEVER sunset a public API version with less than 6 months notice
  3. NEVER mix versioning strategies in the same API (URL path for some, headers for others)
  4. NEVER use minor or patch versions in URL paths (/api/v1.2/ is wrong — use /api/v1/)
  5. NEVER version individual endpoints independently — version the entire API surface as a unit
  6. NEVER deploy a breaking change under an existing version number, even if "nobody uses that field"
  7. NEVER skip documenting differences between versions — every breaking change needs a migration guide entry

Files

2 total
Select a file
Select a file to preview.

Comments

Loading comments…