소스 정보
- 저장소
- tools-only/X-Skills
- 최근 소스 활동
- 2026년 2월 9일 04:08
- 감지된 SKILL.md 언어
- 영어
- 스타
- 7
- 포크
- 1
설치 방법
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
소스 파일 검토
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
메뉴
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
직접 명령은 검토 Prompt를 거치지 않습니다. 실행하기 전에 소스를 확인하세요.
npx skills add https://github.com/tools-only/X-Skills --skill manage-api-versions명령은 한 줄로 유지됩니다. 복사하기 전에 가로로 스크롤해 전체 내용을 확인하세요.
로컬 사본을 원하시나요? SkillsMP에서 현재 제공할 수 있는 파일을 다운로드하세요.
SKILL.md 표시 중
SOC 직업 분류 기준
| 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