API 버전 관리 모범 사례? [닫은]


877

웹 서비스 REST API 버전 관리에 대한 알려진 방법이나 모범 사례가 있습니까?

AWS는 엔드 포인트의 URL을 기준으로 버전 관리를 수행하는 것으로 나타났습니다 . 이것이 유일한 방법입니까, 아니면 같은 목표를 달성 할 수있는 다른 방법이 있습니까? 여러 가지 방법이 있다면 각 방법의 장점은 무엇입니까?

답변:


682

이것은 좋고 까다로운 질문입니다. URI 디자인 주제는 동시에 REST API의 가장 두드러진 부분 이므로 해당 API 사용자에 대한 잠재적 장기 약속 입니다.

응용 프로그램의 진화와 API의 수명 이 줄어들고 API는 프로그래밍 언어와 같이 복잡해 보이는 제품의 진화와 비슷하기 때문에 URI 디자인 에는 자연스러운 제약없어야합니다. 시간이 지남에 따라 . 애플리케이션 및 API 수명이 길수록 애플리케이션 및 API 사용자에 대한 헌신이 커집니다.

반면에, 삶의 또 다른 사실은 API를 통해 소비 될 모든 자원과 그들의 측면을 예측하기 어렵다는 것입니다. 운 좋게도 Apocalypse 까지 사용될 전체 API를 디자인 할 필요는 없습니다 . 모든 자원 엔드 포인트 및 모든 자원 및 자원 인스턴스의 주소 지정 체계를 올바르게 정의하면 충분합니다.

시간이 지남에 따라 각 특정 리소스에 새로운 리소스와 새로운 속성을 추가해야 할 수도 있지만, 리소스 주소 지정 체계가 공개되어 최종적으로 API 사용자가 특정 리소스에 액세스하기 위해 따르는 방법은 변경되지 않아야합니다.

이 방법은 HTTP 동사 시맨틱 (예 : PUT은 항상 업데이트 / 교체해야 함) 및 이전 API 버전에서 지원되는 HTTP 상태 코드 (인간 개입없이 작업 한 API 클라이언트가 계속 작동 할 수 있도록 계속 작동해야 함)에 적용됩니다. 그런 식으로).

또한 API 버전을 URI에 포함하면 시간이 지남에 따라 변경되는 리소스 주소 / URI를 가짐으로써 애플리케이션 상태 엔진 (Roy T. Fieldings PhD 논문에 명시되어 있음) 으로서 하이퍼 미디어 개념이 중단되므로 API가 API 사용자가 의존 할 수 있는 자원 URI는 영구 링크이어야 함을 의미하므로 버전을 자원 URI에 오랫동안 유지해서는 안됩니다 .

물론, 기본 URI에 API 버전을 포함 할 수 있지만 새 API 버전에서 작동 하는 API 클라이언트 디버깅과 같이 합리적이고 제한된 용도로만 사용할 수 있습니다. 이러한 버전이 지정된 API는 시간 제한이 있으며 제한된 API 사용자 그룹 (예 : 비공개 베타 버전)에서만 사용할 수 있어야합니다. 그렇지 않으면, 당신은 당신이하지 말아야 자신을 저지른 다.

만료 날짜가있는 API 버전의 유지 관리에 대한 몇 가지 생각. 웹 서비스 (Java, .NET, PHP, Perl, Rails 등)를 구현하는 데 일반적으로 사용되는 모든 프로그래밍 플랫폼 / 언어를 통해 웹 서비스 엔드 포인트를 기본 URI에 쉽게 바인딩 할 수 있습니다. 이런 방식 으로 파일 / 클래스 / 메소드 모음 을 서로 다른 API 버전간에 쉽게 수집하고 보관할 수 있습니다 .

API 사용자 POV의 경우 이처럼 분명하지만 제한된 시간 동안 만 (예 : 개발 중) 특정 API 버전으로 작업하고 바인딩하는 것이 더 쉽습니다.

API 관리자의 POV에서 파일에 대해 가장 작은 단위 (소스 코드) 버전 관리로 주로 작업하는 소스 제어 시스템을 사용하여 서로 다른 API 버전을 병렬로 유지하는 것이 더 쉽습니다.

그러나 URI에 API 버전이 명확하게 표시되면주의해야 할 점이 있습니다. URI 히스토리에서 API 히스토리가 표시 / 부모 되기 때문에 시간지남 에 따라 REST 지침에 위배되는 변경이 발생하기 때문에이 방법에 반대 할 수도 있습니다 . 동의한다!

이 합리적인 이의 제기를 해결하는 방법은 버전이없는 API 기본 URI에서 최신 API 버전을 구현하는 것입니다. 이 경우 API 클라이언트 개발자는 다음 중 하나를 선택할 수 있습니다.

  • 최신 버전에 대비하여 개발하십시오 ( 잘못 설계된 API 클라이언트를 손상시킬 수있는 최종 API 변경으로부터 애플리케이션을 보호하기 위해 애플리케이션을 유지하기 위해 스스로 노력 ).

  • 제한된 시간 동안 만 특정 버전의 API에 바인딩 (명확 해짐)

예를 들어, API v3.0이 최신 API 버전 인 경우 다음 두 개는 별명이어야합니다 (즉, 모든 API 요청과 동일하게 작동 함).

http : // shonzilla / api / customers / 1234 
http : // shonzilla / api /v3.0 / customers / 1234
http : // shonzilla / api / v3 / customers / 1234

또한 사용 중인 API 버전이 더 이상 사용되지 않거나 더 이상 지원되지 않는 경우 여전히 이전 API 를 가리 키려고하는 API 클라이언트 에 최신 이전 API 버전을 사용하도록 알려야합니다 . 따라서 다음과 같이 사용되지 않는 URI에 액세스하십시오.

http : // shonzilla / api /v2.2 / customers / 1234
http : // shonzilla / api /v2.0 / customers / 1234
http : // shonzilla / api / v2 / customers / 1234
http : // shonzilla / api /v1.1 / customers / 1234
http : // shonzilla / api / v1 / customers / 1234

적절한 버전의 리소스 URI로 리디렉션되는 HTTP 헤더 와 함께 사용되는 리디렉션을 나타내는 30x HTTP 상태 코드 중 하나를 반환해야합니다 Location.

http : // shonzilla / api / customers / 1234

API 버전 관리 시나리오에 적합한 리디렉션 HTTP 상태 코드가 두 개 이상 있습니다.

  • 301 요청 된 URI가있는 자원이 다른 URI (API 버전 정보를 포함하지 않는 자원 인스턴스 영구 링크 여야 함)로 영구적으로 이동했음을 나타 내기 위해 영구적으로 이동했습니다. 이 상태 코드는 사용되지 않거나 지원되지 않는 API 버전을 나타내는 데 사용되어 버전이 지정된 리소스 URI가 리소스 permalink로 대체되었음을 API 클라이언트에 알립니다 .

  • 302 요청한 리소스가 일시적으로 다른 위치에 있지만 요청 된 URI가 계속 지원 될 수 있음을 나타냅니다. 이 상태 코드는 버전이없는 URI를 일시적으로 사용할 수없고 리디렉션 주소를 사용하여 요청을 반복해야하는 경우 (예 : APi 버전이 포함 된 URI를 가리키는 경우) 클라이언트에게 계속 사용하도록 요청하려고 할 때 유용합니다. 퍼머 링크).

  • 다른 시나리오는 HTTP 1.1 사양의 리디렉션 3xx 장 에서 찾을 수 있습니다


142
기본 구현이 변경 될 때 URL에 버전 번호를 사용하는 것은 나쁜 습관으로 간주되어서는 안됩니다. "서비스에 대한 인터페이스가 이전 버전과 호환되지 않는 방식으로 변경 될 때 실제로 완전히 새로운 서비스가 생성되었습니다 ... 클라이언트의 관점에서 볼 때 서비스는 인터페이스 및 비 기능적 특성에 지나지 않습니다 .. 서비스에 대한 인터페이스가 이전 버전과 호환되지 않는 방식으로 변경되면 더 이상 원래 서비스의 인스턴스를 나타내지 않고 완전히 새로운 서비스입니다. " ibm.com/developerworks/webservices/library/ws-version
benvolioT

7
클라이언트 나 개발자가 확인할 수 있도록 버전 번호가있는 헤더를 추가 할 생각이 있습니까?
webclimber

11
클라이언트가 기대하는 버전을 나타 내기 위해 Accept 헤더 사용을 참조하십시오 : blog.steveklabnik.com/2011/07/03/…
Weston Ruter

52
마지막 부분 : 410 Gone리디렉션이 새 위치가 호환되지 않을 때 리디렉션 할 수 있기 때문에 더 이상 지원되지 않고 더 이상 지원되지 않는 API가 반환해야한다고 말하고 싶습니다 . API가 단순히 폐기되었지만 여전히 존재 Warning하는 경우 응답 의 HTTP 헤더가 옵션 일 수 있습니다.
Michael Stum

22
shonzilla / api / customers / 1234 와 같은 안정적인 URL을 이미 사용하고 있고 새 버전으로 업그레이드하려는 클라이언트를 어떻게 처리 합니까? 어떻게 URL에 V2 (이전 버전)를 추가하도록 할 수 있습니까?
Dejell

273

URL에는 버전이 포함되지 않아야합니다. 버전은 요청한 리소스의 "아이디어"와 관련이 없습니다. URL을 원하는 개념의 경로로 생각해야합니다. 항목을 반환하려는 방식이 아닙니다. 버전은 객체의 개념이 아니라 객체의 표현을 나타냅니다. 다른 포스터가 말했듯이 요청 헤더에 형식 (버전 포함)을 지정해야합니다.

버전이있는 URL에 대한 전체 HTTP 요청을 보면 다음과 같습니다.

(BAD WAY TO DO IT):

http://company.com/api/v3.0/customer/123
====>
GET v3.0/customer/123 HTTP/1.1
Accept: application/xml

<====
HTTP/1.1 200 OK
Content-Type: application/xml
<customer version="3.0">
  <name>Neil Armstrong</name>
</customer>

헤더에는 요청한 표현이 포함 된 행이 포함됩니다 ( "Accept : application / xml"). 그것이 버전이 있어야하는 곳입니다. 모두가 당신이 다른 형식으로 같은 것을 원할 수도 있고 고객이 원하는 것을 요청할 수 있어야한다는 사실을 좋아하는 것 같습니다. 위의 예에서 클라이언트가 요구되는 어떠한 하지 정말 원하는 것을의 진정한 표현 - 자원의 XML 표현입니다. 이론적으로 서버는 요청이 XML 인 한 요청과 완전히 관련이없는 것을 반환 할 수 있으며 그것이 잘못되었다는 것을 파싱해야합니다.

더 좋은 방법은 다음과 같습니다.

(GOOD WAY TO DO IT)

http://company.com/api/customer/123
===>
GET /customer/123 HTTP/1.1
Accept: application/vnd.company.myapp.customer-v3+xml

<===
HTTP/1.1 200 OK
Content-Type: application/vnd.company.myapp-v3+xml
<customer>
  <name>Neil Armstrong</name>
</customer>

또한 클라이언트가 XML이 너무 장황하다고 생각하고 이제 JSON을 원한다고 가정 해 봅시다. 다른 예에서는 동일한 고객에 대한 새 URL이 있어야하므로 다음과 같이 끝납니다.

(BAD)
http://company.com/api/JSONv3.0/customers/123
  or
http://company.com/api/v3.0/customers/123?format="JSON"

(또는 비슷한 것). 실제로 모든 HTTP 요청에는 원하는 형식이 포함됩니다.

(GOOD WAY TO DO IT)
===>
GET /customer/123 HTTP/1.1
Accept: application/vnd.company.myapp.customer-v3+json

<===
HTTP/1.1 200 OK
Content-Type: application/vnd.company.myapp-v3+json

{"customer":
  {"name":"Neil Armstrong"}
}

이 방법을 사용하면 훨씬 더 자유롭게 디자인 할 수 있으며 실제로 REST의 원래 아이디어를 준수 할 수 있습니다. 클라이언트를 방해하지 않고 버전을 변경하거나 API가 변경됨에 따라 클라이언트를 점진적으로 변경할 수 있습니다. 표현 지원을 중단하기로 선택하면 HTTP 상태 코드 또는 사용자 정의 코드로 요청에 응답 할 수 있습니다. 클라이언트는 또한 응답이 올바른 형식인지 확인하고 XML을 검증 할 수 있습니다.

다른 많은 장점이 있으며 여기 내 블로그에서 그 중 일부를 설명합니다. http://thereisnorightway.blogspot.com/2011/02/versioning-and-types-in-resthttp-api.html

URL에 버전을 배치하는 방법이 나쁜지 보여주는 마지막 예입니다. 객체 내부에 정보가 필요하고 다양한 객체의 버전을 지정했다고 가정합니다 (고객은 v3.0, 주문은 v2.0, shipto 객체는 v4.2). 클라이언트에 제공해야하는 불쾌한 URL은 다음과 같습니다.

(Another reason why version in the URL sucks)
http://company.com/api/v3.0/customer/123/v2.0/orders/4321/

10
Accept 헤더에서 독립적 인 데이터 계약 버전 및 서비스 계약 버전을 처리하는 것은 URL에서 지저분한 것처럼 복잡합니다. 다른 옵션이 있습니까? 또한 여러 끝점 (비누, 휴식)이있는 경우 수락에도 표시되어야하며 서버 끝의 라우팅 서비스가 올바른 끝점으로 방향을 결정하도록하십시오. 또는 끝점을 URL로 코딩하는 것이 허용됩니까?
ideafountain

117
적어도 당신의 마지막 이유까지는 이것에 동의 할 수 없습니다. 이것은 URI의 다른 부분이 다른 버전을 가지고 있다고 말하고있는 것 같습니다. 그러나 그것은 API 버전의 요점이 아닙니다. 요점은 ENTIRE 자원에 대한 하나의 버전을 갖는 것입니다. 버전을 변경하면 다른 API 리소스입니다. 따라서 company.com/api/v3.0/customer/123/v2.0/orders/4321 을 보는 것이 합리적이지 않고 오히려 company.com/api/v3.0/customer/123/orders/4321 을 보는 것이 합리적입니다 . 리소스의 특정 부분을 버전 화하지 않고 리소스 전체를 버전 화합니다.
fool4jesus

90
헤더에 버전 번호를 사용하는 것이 더 좋습니다. 그러나 URL을 사용하는 것이 훨씬 더 실용적입니다. 오류가 적고 디버깅이 잘되고 개발자가 쉽게 볼 수 있으며 나머지 테스트 클라이언트에서 쉽게 수정할 수 있습니다.
Daniel Cerecedo

7
나는 BAD / GOOD가 질문을 단순화한다고 생각합니다. API는 "응용 프로그램 프로그래밍 인터페이스"를 나타내며 버전 관리 인터페이스는 매우 좋은 아이디어 인 것 같습니다. API는 실제로 리소스를 제공하는 것이 아닙니다. 분리해야 할 것은 일부 사람들이 인터페이스에 대해 이야기하고 다른 사람들이 리소스에 대해 이야기하고 있다는 것입니다. 네트워크 탭에서 Google지도 API를 자세히 보면 URL에 API 버전 번호가 포함되어 있음을 알 수 있습니다. 예 : 인증 중 maps.google.com/maps/api/jsv2 jsv2는 API 번호입니다.
Tom Gruner

6
@Gili : 사실, 당신은 더 이상 사용한다 -x가에 의해 사용되지 않는 것으로 RFC6648 .
Jonathan W

98

URL에 버전을 넣는 것이 실용적이고 유용하다는 것을 알았습니다. 사용중인 내용을 한 눈에 쉽게 알 수 있습니다. 허용되는 답변에서 알 수 있듯이 사용 편의성, 더 짧거나 더 깨끗한 URL 등을 위해 / foo를 / foo / (최신 버전)에 별칭으로 사용합니다.

이전 버전과의 호환성을 영원히 유지하는 것은 종종 비용이 많이 들고 어렵습니다. 더 이상 사용되지 않음, 여기에 제안 된 리디렉션, 문서 및 기타 메커니즘에 대한 고급 정보를 제공하는 것이 좋습니다.


5
수락 된 답변은 정확하고 가장 순수 할 수 있습니다. 그러나 개발자와 API 사용자는 매일 사용하고 설정하는 것이 가장 쉽습니다. 가장 실용적인 접근 방식. 다른 Google 및 Amazon에서 알 수 있듯이이 방법을 사용하십시오.
무하마드 Rehan 사이드

46

리소스 표현을 버전 화하는 것이 REST 접근법을 따르는 것이 더 낫다는 것에 동의하지만 ... 사용자 정의 MIME 유형 (또는 버전 매개 변수를 추가하는 MIME 유형)의 큰 문제 중 하나는 HTML 및 자바 스크립트.

예를 들어, 리소스를 만들기 위해 IMO가 HTML5 양식으로 다음 헤더를 사용하여 POST 할 수 없습니다.

Accept: application/vnd.company.myapp-v3+json
Content-Type: application/vnd.company.myapp-v3+json 

에서 HTML5 때문입니다 enctype속성은 평소보다 다른 것을 따라서, 열거입니다 application/x-www-formurlencoded, multipart/form-data그리고 text/plain유효하지 않습니다.

... HTML4의 모든 브라우저에서 지원되는지 확실하지 않습니다 (더 느슨한 encytpe 속성을 가지고 있지만 MIME 유형이 전달되었는지 여부에 대한 브라우저 구현 문제임)

이 때문에 버전에 가장 적합한 방법은 URI를 통한 것이라고 생각하지만 '올바른'방법이 아니라는 것을 인정합니다.


14
헤더에서 버전 관리가 정의 된 경로를 가정하면 기본 양식 제출을 사용하는 HTML 양식은 준수하려는 특정 버전을 전달하지 않으므로 항상 최신 버전의 API를 사용한다고 말할 수 있습니다. 그러나 XHR 요청은 실제로 수락을 변경하고 내용 유형 헤더를 읽을 수 있도록합니다. 따라서 기본 형식은 실제로 유일한 문제입니다.
Kyle Hayes

URI가 가장 적절하다는 데 동의하지는 않지만 Content-Type이 양식에서 작동하지 않는다는 사실은 실제로 매우 중요합니다.
wprl

2
@Kyle, 나는 어딘가에 블로그가 요청 헤더에 버전을 지정하지 않으면 가장 좋은 호환성을 위해 최신 버전이 아닌 첫 번째 API 버전으로 반환하는 것이 가장 좋습니다.
andy

그것은 제가 생각하기에 실제로 저에게 많은 의미가 있습니다.
Kyle Hayes

@KyleHayes는 iframe, 비디오 / 내장 및 기타 "src / href"유형 태그를 잊지 않습니다.
pllee

21

URI에 버전을 넣으십시오. 한 버전의 API는 다른 유형의 유형을 항상 지원하지는 않으므로 리소스가 한 버전에서 다른 버전으로 마이그레이션된다는 주장은 잘못되었습니다. XML에서 JSON으로 형식을 전환하는 것과는 다릅니다. 유형이 존재하지 않거나 의미 적으로 변경되었을 수 있습니다.

버전은 리소스 주소의 일부입니다. 한 API에서 다른 API로 라우팅 중입니다. 헤더에서 주소 지정을 숨기는 것은 RESTful하지 않습니다.


13

REST API에서 버전 관리를 수행 할 수있는 몇 가지 위치가 있습니다.

  1. 언급 한 바와 같이, URI에서. 방향 전환 등을 잘 사용하면 다루기 쉽고 심미적으로도 즐거울 수 있습니다.

  2. Accepts : 헤더에서 버전은 파일 형식입니다. 'mp3'대 'mp4'와 같습니다. 이것은 또한 작동하지만 IMO는 조금 덜 잘 작동합니다 ...

  3. 자원 자체에서. 많은 파일 형식에는 일반적으로 헤더에 버전 번호가 포함되어 있습니다. 따라서 지원되지 않는 (최신) 버전이 지정되어 있으면 이전 소프트웨어는 펀트 할 수있는 반면 기존 소프트웨어는 파일 형식의 모든 기존 버전을 이해하여 최신 소프트웨어가 '작동'할 수 있습니다. REST API의 맥락에서 이는 URI를 변경할 필요가 없으며 사용자가 처리 한 특정 버전의 데이터에 대한 응답 만 의미합니다.

세 가지 접근 방식을 모두 사용해야하는 이유를 알 수 있습니다.

  1. 새로운 API를 '클린 스윕'하거나 원하는 방식으로 주요 버전을 변경하려는 경우.
  2. 클라이언트가 PUT / POST를 수행하기 전에 작동하는지 여부를 알기를 원할 경우.
  3. 클라이언트가 작동하는지 확인하기 위해 PUT / POST를 수행해야한다면 괜찮습니다.

8

REST API 버전 관리는 다른 API 버전 관리와 유사합니다. 사소한 변경이 이루어질 수 있으며 주요 변경 사항에는 완전히 새로운 API가 필요할 수 있습니다. 가장 쉬운 방법은 매번 처음부터 시작하는 것입니다. URL에 버전을 넣는 것이 가장 합리적입니다. 클라이언트의 삶을 편하게하려면 더 이상 사용되지 않는 호환성 (영구적 리디렉션), 여러 버전의 리소스 등을 사용하여 이전 버전과의 호환성을 유지하려고합니다.이 방법은보다 까다 롭고 더 많은 노력이 필요합니다. 그러나 "쿨 URI는 변경되지 않습니다"에서 REST가 권장하는 사항이기도합니다.

결국 다른 API 디자인과 같습니다. 고객 편의를 위해 노력하십시오. API에 시맨틱 버전 관리를 채택하면 클라이언트가 새 버전과의 하위 호환성을 명확하게 알 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.