"API에 독립적인 소비자가 생기면 공통 정책, 호환성, 지원 중단이라는 운영 문제가 따라와. 게이트웨이는 여러 서비스의 공통 정책을 모을 수 있고, 명확한 수명 주기 절차는 소비자가 예측 가능하게 이전하도록 도와줘."
API 게이트웨이가 하는 일
API 게이트웨이는 하나 이상의 서비스 앞에서 진입점을 제공하고, 여러 API에 일관되게 적용해야 하는 공통 기능을 처리할 수 있어:
- 인증 검증 — 애플리케이션에 도달하기 전에 Bearer 토큰, JWT 서명, API 키를 검사해. 다만 인증과 권한 부여는 다르므로 애플리케이션의 자원별 권한 검사까지 무조건 없애서는 안 돼.
- 요청률 제한 — 사용자, API 키, 엔드포인트 등 정해진 기준에 따라 한도를 적용해. 여러 게이트웨이 인스턴스에서는 일관된 분산 상태가 필요할 수 있어.
- 요청과 응답 변환 — 경로와 헤더를 바꾸거나 제한적인 호환 계층을 제공해. 복잡한 비즈니스 변환을 게이트웨이에 쌓으면 동작을 추적하기 어려워져.
- 관측 가능성 — 공통 로그와 메트릭을 만들고 추적 맥락을 전파해. 애플리케이션 내부에서만 알 수 있는 의미까지 자동으로 관측해 주는 것은 아니야.
- 버전 라우팅 —
/v1/*과/v2/*를 서로 다른 구현이나 배포로 보낼 수 있어. - TLS 종료 — 외부 TLS 연결과 인증서를 중앙에서 관리할 수 있어. 내부 구간도 위협 모델과 규정에 따라 TLS나 상호 TLS가 필요할 수 있으므로 평문 HTTP를 당연하게 가정하면 안 돼.
- 캐시 — 캐시 가능한 응답의 키, 권한, Vary 의미, 무효화 정책을 정확히 설계했을 때 게이트웨이 계층에서 부하를 줄일 수 있어.
Kong, AWS API Gateway, Azure API Management, Apigee, Cloudflare Workers, Tyk 등이 선택지야. 배포 환경, 지연 시간, 고가용성, 정책 표현력, 비용, 공급자 종속성, 운영 역량을 함께 비교해야 해. 게이트웨이 자체가 병목이나 넓은 장애 지점이 될 수 있으므로 우회 경로와 용량 계획도 필요해.
단일 서비스에서의 대안
서비스가 하나이거나 규모가 작다면 게이트웨이보다 애플리케이션 미들웨어가 단순할 수 있어. FastAPI의 add_middleware나 Express의 app.use로 공통 처리를 구성할 수 있지. FastAPI의 APIRouter(prefix=...)는 여러 라우트에 경로 접두사를 붙여 구성하는 기능일 뿐, 버전 간 호환성이나 지원 중단 정책, 트래픽 분할을 자동으로 관리해 주는 기능은 아니야. 게이트웨이를 검토할 신호는 다음과 같아:
- 여러 서비스에 같은 정책을 일관되게 적용해야 해.
- 공개 URL을 유지하면서 뒤의 구현이나 배포 대상을 바꿔야 해.
- 많은 API에서 키 발급, 사용량 추적, 폐기를 중앙에서 관리해야 해.
- 인증, 요청률 제한, 트래픽 분할 정책이 애플리케이션마다 구현하기에는 복잡해졌어.
처음부터 게이트웨이를 의무로 둘 필요는 없어. 중복 정책과 운영 불일치의 비용이 게이트웨이의 추가 지연, 설정 복잡도, 장애 위험보다 커지는 시점에 도입하면 돼. 직접 접근 가능한 백엔드 경로를 남겨 두면 게이트웨이 정책을 우회할 수 있으므로 네트워크 경계도 함께 설계해야 해.
버전 수명 주기 — 오래 유지할 약속
외부 소비자가 API에 의존하기 시작하면 버전과 지원 기간은 운영 약속이 돼. 이름과 기간은 조직마다 다르지만, 다음과 같은 단계를 명시적으로 관리할 수 있어:
- Beta — 변경 가능성과 지원 범위를 문서에 분명히 적은 조기 접근 단계야. Beta라는 이름만으로 호환성 파괴가 무제한 허용되는 것은 아니므로 실제 정책을 알려야 해.
- Stable — 문서화된 호환성 정책을 적용하는 단계야. 기존 소비자를 깨는 변경은 새 버전이나 별도의 전환 절차로 보내고, 추가 변경도 의미 충돌이 없는지 검토해.
- 지원 중단 공지 —
Deprecation: <date>같은 개념의 기계 판독 신호와 문서, 직접 알림으로 더 이상 권장하지 않는 인터페이스와 전환 시작 시점을 알려. RFC 9745의 실제 Deprecation 값은 HTTP 날짜 문자열이 아니라 Structured Field Date 형식이야. - 종료 예정 공지 —
Sunset: <date>에 RFC 8594의 HTTP-date를 넣어 해당 시점 이후 응답 제공이 중단될 것으로 예상됨을 알릴 수 있어. 충분한 예고 기간과 대체 경로를 함께 제공해야 해. - 종료 — 엔드포인트의 의미가 사라졌다면
410 Gone과 전환 안내를 반환할 수 있어. 완전히 같은 의미의 새 위치가 있을 때만 Location을 포함한 308 같은 리디렉션을 신중히 검토해.
경로에 v1이나 v2를 넣는 방식만이 버전 관리의 전부는 아니야. 날짜 기반 버전, 헤더 기반 버전 등도 가능하며, 핵심은 한 가지 정책을 문서화하고 사용량을 측정하며 지원 기간, 변경 내역, 전환 가이드, 종료 기준을 일관되게 운영하는 데 있어. Stripe 같은 공개 API의 정책은 좋은 참고 자료지만 그대로 복제하기보다 실제 소비자와 계약에 맞춰야 해.
Sunset 헤더를 적용하는 예
# Endpoint 여전히 동작 하는데 은퇴 표시
GET /v1/users HTTP/1.1
HTTP/1.1 200 OK
Deprecation: Sun, 01 Jan 2026 00:00:00 GMT
Sunset: Wed, 01 Jul 2026 00:00:00 GMT
Link: </v2/users>; rel="successor-version"
Content-Type: application/json
[...]
# Sunset 날짜 후 — endpoint 가 410 돌려줌
GET /v1/users HTTP/1.1
HTTP/1.1 410 Gone
Link: </v2/users>; rel="successor-version"
Content-Type: application/json
{"error":{"code":"endpoint_retired","message":"/v2/users 를 쓰세요. 안내는 https://docs.example.com/migrate-v1-v2 를 보세요"}}
헤더는 자동화 도구가 읽을 신호이고, 문서와 오류 본문은 사람이 실제 이전을 수행할 수 있게 안내해야 해. 위 동결 예제의 Sunset 값은 HTTP-date 형식이지만 Deprecation 값은 RFC 9745 형식이 아니야. 현재 표준에 맞추려면 Deprecation에 @로 시작하는 Structured Field Date를 사용하고, 지원 중단 정책 문서는 Link의 deprecation 관계로 연결하는 방식을 검토해. 아래 동결 FastAPI 코드도 같은 잘못된 날짜 형식을 사용하며, HTTPException의 detail 값은 실제 응답에서 detail 필드에 감싸지므로 위의 error 본문과 그대로 일치하지 않아.