用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/tools-only/X-Skills --skill manage-api-versions命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
基于 SOC 职业分类
正在显示 SKILL.md
| name | manage-api-versions |
| description | Manage API versions with proper migration strategies |
| shortcut | apiv |
Implement comprehensive API versioning strategies with backward compatibility, smooth migration paths, deprecation workflows, and automated compatibility testing to ensure seamless API evolution.
Use /manage-api-versions when you need to:
DON'T use this when:
This command implements URL Path Versioning + Accept Header as the primary approach because:
Alternative considered: Header-Only Versioning
Alternative considered: Query Parameter Versioning
Before running this command:
Select and implement the appropriate versioning mechanism for your API architecture.
Set up routing, middleware, and transformers for multi-version support.
Build backward compatibility adapters and response transformers.
Implement deprecation notices, sunset headers, and migration tools.
Create comprehensive test suites covering all supported versions.
The command generates:
api/v1/ - Version 1 implementationapi/v2/ - Version 2 implementationmiddleware/version-router.js - Version routing logictransformers/ - Version-specific data transformerstests/compatibility/ - Cross-version compatibility testsdocs/migration-guide.md - Version migration documentation// middleware/version-router.js
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, // days before sunset
sunsetPeriod: 180 // days until removal
};
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.());
});
// middleware/content-negotiation.js
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);
// Define supported media types with versions
const supportedTypes = [
'application/vnd.api.v3+json',
'application/vnd.api.v2+json',
'application/vnd.api.v1+json',
'application/json' // Default fallback
];
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;
});
// tests/version-compatibility.test.js
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 | 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 |
Versioning Strategies
url-path: Version in URL path (/v1/)header: Version in Accept headerquery: Version in query parametersubdomain: Version in subdomain (v1.api.example.com)Deprecation Policies
aggressive: 3-month deprecation cyclestandard: 6-month deprecation cycleconservative: 12-month deprecation cycleenterprise: Custom per-client agreementsDO:
DON'T:
// Track version usage
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();
});
/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