1P by GN⁺ | ★ favorite | 댓글 1개
  • 공개 웹 API가 Product API 같은 이름과 /api/v1 경로를 함께 쓰면, API 자체의 시맨틱 버전과 구조가 어긋날 수 있음
  • /v1/ 경로와 major.minor.patch를 병행하면 라우트와 API 계약이 섞이고, 시맨틱 버전의 첫 숫자가 URL에 고정됨
  • 호환성을 깨는 변경에는 새 경로와 리버스 프록시 라우트가 필요해져, 계약 정보가 URL과 버전 번호로 분산될 수 있음
  • 후속 API를 동시에 만들면 기존 API는 사실상 v1에 묶이고, 이후 호환성 깨짐 변경에서 이름과 경로의 의미가 애매해짐
  • 공개 웹 API 버전 관리에서 반복적으로 거슬리는 방식과 더 나은 설계 원칙을 찾으려는 문제의식임

댓글과 토론

Lobste.rs 의견들
  • URL에 /v1/을 두는 건 사실 큰 장점 중 하나임. 엔드포인트를 끄기 전까지는 사용자에게 API를 깨지 않도록 강제하기 때문

  • Evolving HTTP APIs와 같은 저자의 다른 글들이 유용한 조언을 줌

  • 기본적으로 각 라우트에 /v1/, /v2/처럼 붙여 호환성 깨짐 변경을 표시함. 여러 호스트에서 동작하는 표준을 정의하려는 게 아닌 공개 운영 API라면 완전한 의미적 버전 관리(semantic versioning)를 할 이유가 별로 없음
    의미적 버전 관리는 다른 개발자가 변경 로그를 20분씩 읽지 않고도 의존성을 자신 있게 올릴 수 있게 하려고 존재하는데, 운영 중인 API에서는 사람들이 새 마이너 버전이나 버그 수정 버전을 언제 가져올지 선택할 수 없음
    무엇이 호환성 깨짐 변경인지는 문서화된 동작을 바꾸거나, 문서화된 동작에 의존하는 기존 클라이언트를 깨뜨리는 경우로 봄. 문서화되지 않은 동작 변경까지 깨짐으로 보는 곳도 있지만, 거기엔 위험이 많음

  • Google에서는 이렇게 함: AIP-185: API Versioning, AIP-180: Bacwards compatibility
    이 설계 문서들은 Google의 업무 방식에 꽤 특화되어 있다고 느끼지만, API를 설계할 때 참고해 왔고 그 안의 몇몇 아이디어는 매우 유용했음

  • 일반적으로 모든 API는 호환성 깨짐 변경을 최대한 줄이려 노력해야 한다고 봄. 예를 들어 속성 이름을 바꾸고 싶다면 기존 속성을 없애기보다 새 이름을 중복으로 추가하는 편이 낫다고 생각함
    다만 the people at Buttondown do it 방식도 깔끔함. API 버전 간 마이그레이션을 정의해서, 소비자는 헤더로 자기 API 버전을 고정할 수 있고 제공자는 계속 변경을 진행할 수 있게 함

    • 출력 속성에는 속성을 중복하는 방식이 꽤 잘 먹혔음. 하지만 입력에서는 클라이언트가 두 속성을 서로 다른 값으로 보내는 경우를 처리해야 함
      “새 이름이 항상 우선”이라는 답이 떠오르지만, 클라이언트가 읽기-수정-쓰기 순서를 수행하면서 서버가 만든 객체의 수정본을 다시 보내는 경우엔 무너질 수 있음. 클라이언트가 예전 속성만 갱신하고 새 속성은 무시한 채 그대로 되돌려 보낼 수 있기 때문
    • API 제공자가 설명한 것처럼 API 버전 간 마이그레이션을 제공하는 건 좋아 보이지만, using an HTTP request header for versioning can cause problems
    • 그 링크는 데이터 형태를 다루는 방법을 아주 잘 설명함. 다만 그건 일부일 뿐이고, 동작 자체가 바뀔 때는 어떻게 하는지 궁금함
      그런 변환을 동작 할당에도 쓸 수 있을 것 같지만, 놓친 게 아니라면 그 부분은 다루지 않았음
  • 이상적으로는 버전을 경로에 포함하고, 새 버전은 추가적인 성격을 갖게 만들어야 함. 그러면 예전 버전 API가 필요한 입출력 변환을 거쳐 요청을 더 새 API 버전으로 재라우팅할 수 있음
    몇 년 뒤 어떤 오래된 버전도 아무도 쓰지 않게 되면 제거할 수 있고, /v1/ 경로는 오류가 됨

  • 예전에 Accept 헤더를 통한 콘텐츠 협상으로 API 버전 관리를 하는 방식을 조금 읽어 봤음. 그런 방식으로 API 버전 관리를 해 본 사람이 있다면 경험이 궁금함
    내 경험상 리소스별 버전 관리나 전역 버전 관리가 가장 직관적인 방식에 가까웠음. 폐기에는 Deprecation HTTP 응답 헤더(RFC 9745)를 쓰고, 결국 오래된 엔드포인트에는 410 Gone 같은 응답을 반환하는 조합이 클라이언트가 새 버전으로 옮겨가게 하는 합리적인 방법으로 보임
    추가로, 누군가 진화 가능한 API를 만들어 봤는지도 정말 궁금함. 예전 버전 요청을 내부에서 새 API 버전 요청으로 번역해 주다가, 클라이언트가 이전하거나 일정 시간이 지나면 실제로 예전 버전을 제거하는 방식 말임