API 버전 관리 논쟁은 대개 엉뚱한 쪽에서 시작됩니다. 버전 번호를 어디에 둘 것인가 하는 문제 말입니다. 이 주제 전체에서 결과에 가장 영향이 작은 결정이 바로 그것입니다. 정작 중요한 것은 어떤 변경이 애초에 새 버전을 요구하는가이며, 대부분의 팀은 이 지점에서 안이한 쪽으로 판단을 그르칩니다. 순수하게 추가만 했다고 믿는 것을 배포했는데, 어느 클라이언트가 깨집니다.

쓸 만한 사고 모형은 이렇습니다. 여러분의 API는 호출자가 무엇에 기댈 수 있는지에 대한 약속입니다. 합리적인 호출자가 기대고 있던 무언가를 무효로 만든다면 그 변경은 호환성을 깨는 변경입니다. 그리고 호출자는 문서가 명시적으로 허용한 것보다 훨씬 많은 것에 기대고 있습니다.

모두가 걸려 넘어지는 변경: 응답에 필드를 하나 추가하는 일입니다. 추가일 뿐이고, 잘 작성된 클라이언트는 이 때문에 깨지지 않으며, 그런데도 실제 클라이언트는 이 때문에 정기적으로 깨집니다. 일부가 응답을 엄격하게 검증하고 모르는 필드를 거부하기 때문입니다. 그것이 여러분의 잘못인지 상대의 잘못인지는, 상대의 연동이 멈추고 전화가 울리는 순간부터 아무 의미가 없습니다.


무엇이 실제로 호환성을 깨는가

의심의 여지 없이 깨는 변경: 필드를 제거하거나 이름을 바꾸는 것, 필드의 타입을 바꾸는 것, 필수 요청 파라미터를 추가하는 것, 검증을 조이는 것, 기존 값의 의미를 바꾸는 것, 그리고 호출자가 분기하는 상태 코드를 바꾸는 것입니다.

안전해 보이지만 실제로는 깨는 변경: 클라이언트가 엄격하게 검증할 때 응답에 필드를 추가하는 것. 약속한 적은 없지만 호출자가 당연하게 여겨 온 배열 순서를 바꾸는 것. 누군가 문자열로 비교하고 있는 오류 메시지를 바꾸는 것. 동기 동작을 비동기로 바꾸는 것.

정말로 안전한 변경: 선택적인 요청 파라미터를 새로 추가하는 것, 새 엔드포인트를 추가하는 것, 검증을 완화하는 것, 그리고 열거형에 새 값을 추가하는 것입니다. 다만 마지막 항목은 모르는 값이 올 수 있다고 클라이언트에게 미리 알렸고 실제로 그것을 처리하는지 확인할 수 있을 때만 해당합니다.

여기서 드러나는 규칙은, 안전함이 명세가 허용하는 바가 아니라 호출자가 실제로 하는 일에 달려 있다는 것입니다. 모든 클라이언트를 여러분이 통제한다면 확인할 수 있습니다. 그렇지 않다면, 여러분이 부수적이라고 여긴 바로 그것에 누군가 기대고 있다고 가정하십시오. 실제로 그렇기 때문입니다.

API 버전 관리 전략과 각각의 비용

URL에 버전을 넣는 방식. 가장 흔한 접근이며, 장점은 눈에 보인다는 것입니다. /v1/orders/v2/orders는 누가 봐도 다른 리소스입니다. 대가는 API 전체의 버전 올림을 부추긴다는 점입니다. 엔드포인트 하나에만 생긴 변경이 나머지 전부를 끌고 가고, 클라이언트는 한꺼번에 이전해야 합니다.

헤더에 버전을 넣는 방식. URL을 안정적으로 유지하고 더 잘게 나눌 수 있지만, 대신 보이지 않습니다. 일부러 찾아보지 않는 한 브라우저나 로그 한 줄에서 버전을 볼 수 없고, 헤더를 빠뜨린 호출자는 여러분이 정한 기본값을 받게 됩니다. 그 기본값은 의도를 갖고 결정해야 하는 사항입니다.

날짜 기반 버전 관리. 호출자가 날짜를 고정하면 그 시점의 동작 그대로 API를 받습니다. Stripe가 이 방식을 문서화하고 있는데, 계정마다 기본 버전이 있고 요청 단위로 이를 덮어쓸 수 있습니다. 이전 단계를 가능한 한 잘게 쪼개 주는 대신, 호환성 부담을 여러분의 코드베이스로 옮깁니다. 이제 그 코드베이스가 버전 사이의 변환을 계속 유지해야 합니다.

버전을 두지 않고 추가만 하는 방식. 아무것도 제거하지 않겠다고 진심으로 약속할 수 있다면 충분히 현실적이고 과소평가된 선택입니다. 대가는 지울 수 없는 필드가 쌓이고 바로잡을 수 없는 동작이 남는다는 것입니다. 급한 청구서가 아니라 느리게 새는 세금에 가깝습니다.

정답은 없고, 여러분의 이전 부담과 고객의 이전 부담 사이의 교환만 있습니다. 날짜 기반 버전 관리는 호출자에게 가장 친절하고 운영하기에 가장 비쌉니다. URL 버전 관리는 정확히 그 반대입니다.

깨는 변경을 견딜 만하게 만들기

먼저 넓히고 나중에 줄이십시오. 기존 필드 옆에 새 필드를 추가하고, 둘 다 채우고, 클라이언트에게 옮길 시간을 주고, 나중 버전에서 예전 것을 제거하십시오. 이렇게 하면 깨는 변경 하나가 안전한 변경 두 개가 되고, 그 한 단계를 더 밟는 값어치는 거의 언제나 있습니다.

누가 무엇을 쓰는지 계측하십시오. 누가 아직 그 버전 위에 있는지 모른 채로는 버전을 안전하게 내릴 수 없습니다. 모든 요청에 버전과 클라이언트 신원을 함께 기록하십시오. 그래야 지원 종료가 어둠 속으로 던지는 공지가 아니라 근거에 기반한 대화가 됩니다.

이메일만이 아니라 메커니즘으로 알리십시오. DeprecationSunset 응답 헤더를 쓰면 클라이언트가 종료 날짜를 프로그램으로 알아낼 수 있습니다. 아무도 더는 보지 않는 주소로 보낸 메시지보다 눈에 띌 가능성이 훨씬 큽니다.

현실적인 기간을 주십시오. 연동은 다른 우선순위를 가진 사람들이 유지보수합니다. 그들의 릴리스 주기보다 짧은 마감은 그냥 지나갑니다. 공개 API라면 여섯 달이 흔하고, 직접 이야기해 본 소수의 알려진 파트너라면 그보다 짧아도 무리가 없습니다.

구버전 내리기

위에서 말한 계측이 있어야 이 단계가 가능해집니다. 날짜를 공지하고, 트래픽이 줄어드는 것을 지켜보고, 아직 옮기지 않은 호출자에게 이름을 불러 가며 연락하십시오.

긴 꼬리를 예상하십시오. 고객사 안에서 아무도 자기 것이라고 기억하지 못하는 연동이 있을 것이고, 그것들은 여러분이 버전을 끄는 순간에 발견됩니다. 여기서는 짧은 정전이 도움이 됩니다. 최종일 이전에 미리 알린 시간대에 구버전을 잠깐 꺼 두면, 누군가 예상하고 있는 동안 장애가 나지 바쁜 시기 한복판에 나지 않습니다.

솔직한 입장은, 일부 호출자는 구버전이 완전히 멈춘 뒤에야 움직인다는 것입니다. 놀라는 대신 그것을 전제로 계획하고, 실패했을 때 나가는 것이 타임아웃이 아니라 무슨 일이 일어났는지 설명하는 분명한 오류가 되도록 하십시오.

필요 없는 버전

대부분의 내부 API에는 버전 관리가 전혀 필요하지 않습니다. 호출자를 전부 여러분이 통제하고 양쪽을 함께 바꿀 수 있기 때문입니다. 자기 서비스 두 개가 쓰는 인터페이스에 버전 협상을 붙이는 것은, 비용은 들면서 아무것도 막아 주지 않는 장치입니다.

필요해지는 시점은 모든 소비자를 한 번에 배포할 수 없게 되는 때입니다. 상대가 다른 팀이든, 다른 릴리스 주기든, 다른 회사든 마찬가지입니다. 그것이 진짜 방아쇠이며, API가 얼마나 공개적인지와는 아무 상관이 없습니다. 저희 서버리스 API 가이드의 설계 고려 사항은 엣지에서도 똑같이 적용됩니다.

Mecanik은 소프트웨어 개발 업무의 일부로 이런 API를 설계하고 유지보수합니다. 버전 체계 자체가 흥미로운 결정인 경우는 드뭅니다. 어느 호출자가 아직 구버전에 남아 있는지 아는 일은 언제나 흥미롭습니다.



자주 묻는 질문

무엇이 호환성을 깨는 API 변경인가요? 필드를 제거하거나 이름을 바꾸는 것, 필드 타입을 바꾸는 것, 필수 파라미터를 추가하는 것, 검증을 조이는 것, 값의 의미를 바꾸는 것, 호출자가 분기하는 상태 코드를 바꾸는 것입니다. 실제로 깨는 경우도 있습니다. 클라이언트가 엄격하게 검증할 때 응답 필드를 추가하는 것, 호출자가 당연하게 여기던 배열 순서를 바꾸는 것, 누군가 비교하고 있는 오류 메시지 문구를 고치는 것입니다.

API 버전은 URL에 넣어야 하나요, 헤더에 넣어야 하나요? URL 버전 관리는 눈에 보이고 단순하지만 API 전체의 버전 올림을 부추기고 클라이언트가 한꺼번에 이전하도록 강요합니다. 헤더 버전 관리는 URL을 안정적으로 유지하고 더 잘게 나눌 수 있지만 로그와 브라우저에서 보이지 않으며, 헤더를 빠뜨린 호출자를 위한 기본값을 의도적으로 정해야 합니다. 어느 쪽도 틀리지 않았고, 여러분의 이전 부담과 고객의 부담을 맞바꿀 뿐입니다.

날짜 기반 API 버전 관리란 무엇인가요? 호출자가 날짜를 고정하면 그 시점의 동작 그대로 API를 받는 방식이며, Stripe가 계정별 기본 버전을 두고 개별 요청이 이를 덮어쓸 수 있게 한 것이 그 예입니다. 클라이언트에게는 가능한 한 작은 이전 단계를 주고, 호환성 부담은 여러분의 코드베이스로 옮겨 버전 사이의 변환을 계속 유지하게 만듭니다.

API 지원 종료 기간은 얼마나 잡아야 하나요? 공개 API라면 여섯 달이 흔하고, 직접 이야기해 본 소수의 알려진 파트너라면 그보다 짧아도 무리가 없습니다. 연동은 다른 우선순위를 가진 사람들이 유지보수하므로, 그들의 릴리스 주기보다 짧은 기간은 아무리 분명하게 공지해도 지나가 버립니다.

내부 API도 버전 관리가 필요한가요? 대개는 필요하지 않습니다. 호출자를 전부 통제하고 양쪽을 함께 바꿀 수 있기 때문입니다. 버전 관리는 모든 소비자를 한 번에 배포할 수 없게 되는 시점부터 필요해지며, 상대가 다른 팀이든 다른 릴리스 주기든 다른 회사든 마찬가지입니다. 그것이 방아쇠이지 API가 공개인지 여부가 아닙니다.