API 버전 관리 및 하위 호환성은(는) 무엇을 하나요?
기존 소비자를 중단시키지 않고 우아하게 진화하는 API 버전 관리 전략을 설계합니다.
활성화 트리거
활성화 키워드: "API 버전 관리", "하위 호환성", "지원 중단", "변경 사항", "API 마이그레이션", "v1 v2", "sunset 헤더", "API 진화", "비호환 변경"
대상 아님: 데이터 스키마 진화 → schema-evolution-manager | 게이트웨이 버전 라우팅 → api-gateway-reverse-proxy-expert | GraphQL 지원 중단 → graphql-server-architect
빠른 시작
- 변경 사항 분류 — 추가(안전), 수정(잠재적 중단), 제거(중단)
- 전략 선택 — URL 경로(
/v2/), 헤더(API-Version), 또는 콘텐츠 협상 - Sunset 헤더 구현 — RFC 8594는 소비자에게 이전 버전의 종료 시점을 알려줍니다.
- 버전 병행 운영 — 주요 버전 변경 시 최소 6개월 중복 운영
- 도입 모니터링 — 버전별 트래픽을 추적하여 언제 폐기할지 결정
핵심 기능
| 영역 | 기술 |
|---|---|
| URL 버전 관리 | /api/v1/, /api/v2/ 경로 기반 라우팅 |
| 헤더 버전 관리 | API-Version: 2024-01-15, Accept-Version |
| 콘텐츠 협상 | Accept: application/vnd.myapi.v2+json |
| 지원 중단 | Sunset 헤더 (RFC 8594), Deprecation 헤더 |
| 도구 | OpenAPI 3.1 오버레이, Optic, Bump.sh |
아키텍처 패턴
버전 관리 전략 결정 트리
변경 사항이 추가만 있습니까? (새 필드, 새 엔드포인트)
├─ 예 → 버전 범프 불필요 (하위 호환 가능)
└─ 아니오 → 필드 이름 변경/타입 변경인가?
├─ 예 → 기존 필드와 새 필드를 모두 유지할 수 있는가?
│ ├─ 예 → 새 필드 추가, 기존 필드 지원 중단 (마이너 버전)
│ └─ 아니오 → 주요 버전 범프 (v1 → v2)
└─ 아니오 → 제거인가?
└─ 예 → 지원 중단 기간을 포함한 주요 버전 범프
병행 버전 배포
// Express 라우터를 사용한 버전 기반 라우팅
import { Router } from 'express';
const v1Router = Router();
const v2Router = Router();
// v1: { name: string } 반환
v1Router.get('/users/:id', async (req, res) => {
const user = await getUser(req.params.id);
res.json({ name: user.fullName }); // 레거시 형태
});
// v2: { firstName, lastName, displayName } 반환
v2Router.get('/users/:id', async (req, res) => {
const user = await getUser(req.params.id);
res.json({
firstName: user.firstName,
lastName: user.lastName,
displayName: user.fullName,
});
});
app.use('/api/v1', v1Router);
app.use('/api/v2', v2Router);
// v1용 Sunset 헤더 미들웨어
v1Router.use((req, res, next) => {
res.set('Sunset', 'Sat, 01 Nov 2026 00:00:00 GMT');
res.set('Deprecation', 'true');
res.set('Link', '</api/v2>; rel="successor-version"');
next();
});
날짜 기반 버전 관리 (Stripe 모델)
API-Version: 2026-03-15
변경 사항은 정수가 아닌 날짜에 연결됩니다:
2026-01-01 → 기준선
2026-03-15 → `name`을 `display_name`으로 이름 변경
2026-06-01 → `legacy_field` 제거
서버는 버전이 명시되지 않은 요청을 계정의 기본 버전으로 고정합니다.
각 버전은 내부 표준 모델 위의 변환 계층입니다.
안티패턴
- 너무 이른 버전 관리 — 대부분의 변경은 추가적이므로 버전 범프가 필요하지 않습니다. 필드를 자유롭게 추가하세요.
- Sunset 일정 없음 — 구체적인 종료 날짜 없이 지원 중단하면 버전이 영원히 유지됩니다.
- 전체 컨트롤러 복사 — 비즈니스 로직을 버전별로 중복하지 말고 변환/어댑터 계층을 사용하세요.
- 알려지지 않은 필드 무시 — API는 수용적인 리더여야 합니다. 입력에서 알려지지 않은 필드는 무시하세요(Postel의 법칙).
- 마이너 버전에서 호환되지 않는 변경 — 소비자가 의존했다면, 의도와 관계없이 제거는 호환되지 않습니다.
품질 체크리스트
- 추가 변경(새 필드, 새 엔드포인트)은 버전 범프 없이 배포
- 호환되지 않는 변경은 6개월 이상의 지원 중단 기간과 함께 주요 버전 필요
- 지원 중단된 버전에 Sunset 헤더(RFC 8594) 설정
- Link 헤더가 소비자를 후속 버전으로 안내
- 버전별 트래픽 모니터링으로 마이그레이션 진행 상황 추적
- 버전별 OpenAPI 사양 게시 및 diff 도구(Optic/Bump.sh) 사용
- 소비자 알림 계획: 변경 로그, 이메일, 대시보드 경고
- 버전 라우팅은 애플리케이션 코드가 아닌 게이트웨이 수준에서 처리
- 통합 테스트로 하위 호환성 검증(계약 테스트)