development

API 버전 관리에 대한 모범 사례?

big-blog 2020. 9. 28. 09:30
반응형

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


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

AWS가 엔드 포인트의 URL로 버전 관리를 수행하는 것을 확인했습니다 . 이것이 유일한 방법입니까, 아니면 동일한 목표를 달성하는 다른 방법이 있습니까? 방법이 여러 개인 경우 각 방법의 장점은 무엇입니까?


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

응용 프로그램의 발전과 그 API는 삶의 사실이며 프로그래밍 언어와 같이 복잡해 보이는 제품의 발전과도 유사하므로 URI 디자인 은 덜 자연스러운 제약 조건가져야하며 보존되어야합니다. 시간이 지남에 . 애플리케이션과 API의 수명이 길수록 애플리케이션 및 API 사용자에 대한 약속이 커집니다.

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

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

이 방법은 HTTP 동사 의미론 (예 : PUT은 항상 업데이트 / 교체해야 함) 및 이전 API 버전에서 지원되는 HTTP 상태 코드 (사람의 개입없이 작동 한 API 클라이언트가 계속 작동 할 수 있도록 계속 작동해야 함)에 적용됩니다. 그렇게).

또한 URI에 API 버전을 포함하면 시간이 지남에 따라 변경되는 리소스 주소 / URI를 갖게 됨으로써 애플리케이션 상태 (Roy T. Fieldings PhD 논문에 명시 됨)의 엔진으로서 하이퍼 미디어 의 개념이 깨지기 때문에 API 버전은 리소스 URI에 오랫동안 보관되어서는 안됩니다. 즉, API 사용자가 의존 할 수 있는 리소스 URI는 영구 링크 여야합니다 .

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

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

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

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

그러나 API 버전이 URI에 명확하게 표시되는 경우주의 사항 이 있습니다. API 기록이 URI 디자인에서 표시 / 명백해 지므로 시간지남 에 따라 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 버전을 나타내는 데 사용할 수 있으며 API 클라이언트에게 버전이 지정된 리소스 URI가 리소스 영구 링크로 대체되었음을 알립니다 .

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

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


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>

The header contains the line which contains the representation you are asking for ("Accept: application/xml"). That is where the version should go. Everyone seems to gloss over the fact that you may want the same thing in different formats and that the client should be able ask for what it wants. In the above example, the client is asking for ANY XML representation of the resource - not really the true representation of what it wants. The server could, in theory, return something completely unrelated to the request as long as it was XML and it would have to be parsed to realize it is wrong.

A better way is:

(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>

Further, lets say the clients think the XML is too verbose and now they want JSON instead. In the other examples you would have to have a new URL for the same customer, so you would end up with:

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

(or something similar). When in fact, every HTTP requests contains the format you are looking for:

(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"}
}

Using this method, you have much more freedom in design and are actually adhering to the original idea of REST. You can change versions without disrupting clients, or incrementally change clients as the APIs are changed. If you choose to stop supporting a representation, you can respond to the requests with HTTP status code or custom codes. The client can also verify the response is in the correct format, and validate the XML.

There are many other advantages and I discuss some of them here on my blog: http://thereisnorightway.blogspot.com/2011/02/versioning-and-types-in-resthttp-api.html

One last example to show how putting the version in the URL is bad. Lets say you want some piece of information inside the object, and you have versioned your various objects (customers are v3.0, orders are v2.0, and shipto object is v4.2). Here is the nasty URL you must supply in the client:

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

We found it practical and useful to put the version in the URL. It makes it easy to tell what you're using at a glance. We do alias /foo to /foo/(latest versions) for ease of use, shorter / cleaner URLs, etc, as the accepted answer suggests.

Keeping backwards compatibility forever is often cost-prohibitive and/or very difficult. We prefer to give advanced notice of deprecation, redirects like suggested here, docs, and other mechanisms.


I agree that versioning the resource representation better follows the REST approach...but, one big problem with custom MIME types (or MIME types that append a version parameter) is the poor support to write to Accept and Content-Type headers in HTML and JavaScript.

For example, it is not possible IMO to POST with the following headers in HTML5 forms, in order to create a resource:

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

This is because the HTML5 enctype attribute is an enumeration, therefore anything other than the usual application/x-www-formurlencoded, multipart/form-data and text/plain are invalid.

...nor am I sure it is supported across all browsers in HTML4 (which has a more lax encytpe attribute, but would be a browser implementation issue as to whether the MIME type was forwarded)

Because of this I now feel the most appropriate way to version is via the URI, but I accept that it is not the 'correct' way.


Put your version in the URI. One version of an API will not always support the types from another, so the argument that resources are merely migrated from one version to another is just plain wrong. It's not the same as switching format from XML to JSON. The types may not exist, or they may have changed semantically.

Versions are part of the resource address. You're routing from one API to another. It's not RESTful to hide addressing in the header.


There are a few places you can do versioning in a REST API:

  1. As noted, in the URI. This can be tractable and even esthetically pleasing if redirects and the like are used well.

  2. In the Accepts: header, so the version is in the filetype. Like 'mp3' vs 'mp4'. This will also work, though IMO it works a bit less nicely than...

  3. In the resource itself. Many file formats have their version numbers embedded in them, typically in the header; this allows newer software to 'just work' by understanding all existing versions of the filetype while older software can punt if an unsupported (newer) version is specified. In the context of a REST API, it means that your URIs never have to change, just your response to the particular version of data you were handed.

I can see reasons to use all three approaches:

  1. if you like doing 'clean sweep' new APIs, or for major version changes where you want such an approach.
  2. if you want the client to know before it does a PUT/POST whether it's going to work or not.
  3. if it's okay if the client has to do its PUT/POST to find out if it's going to work.

Versioning your REST API is analogous to the versioning of any other API. Minor changes can be done in place, major changes might require a whole new API. The easiest for you is to start from scratch every time, which is when putting the version in the URL makes most sense. If you want to make life easier for the client you try to maintain backwards compatibility, which you can do with deprecation (permanent redirect), resources in several versions etc. This is more fiddly and requires more effort. But it's also what REST encourages in "Cool URIs don't change".

In the end it's just like any other API design. Weigh effort against client convenience. Consider adopting semantic versioning for your API, which makes it clear for your clients how backwards compatible your new version is.

참고URL : https://stackoverflow.com/questions/389169/best-practices-for-api-versioning

반응형