API Versioning
프레임워크/스프링&스프링부트

API Versioning

Rest API 버전관리

Rest API의 설계가 변경되거나 구조가 변경될시 버전을 변경하여 관리를 해줘야한다.

이유는 당연히 기존에 사용하던 하위 버전의 Rest API를 호출하여 사용할 수 없게 될경우 클라이언트측의 코드가 변경되어야하기 때문이다.

 

즉, 기존 사용하던 Rest API를 계속해서 사용하게 해주기 위해 버전을 관리해주어야 한다.

 

언제 관리해야할까?

그러면 API의 버전을 언제 관리해야할까?

보통 api의 버전은 Major와 Minor로 구분하여 상황에 맞추어 버전을 관리하게 된다.

 

Major Version

이전 버전과 호환의 문제가 깨지는 즉, 클라이언트측의 코드가 변경되어야하는 하는 상황으로 본다.

  1. API가 삭제되거나 API URL이 변경되는경우
  2. API의 파라미터가 삭제되거나, 파라미터 명이 변경되는경우
  3. API의 동작이 변경되는 경우
  4. 반환하던 에러코드가 변경되는 경우

위와 같은 케이스들은 전보 기존에 쓰던 API를 사용할 수가 없어 클라이언트측의 코드도 변경되어야하는 상황이며, 위와 같은 상황이 아니더라도 클라이언트측에 어떠한 변화라도 있게 되는 경우에는 Major 버전을 올려줘야한다.

 

Minor Version

Major한 변경이 아닌 그외의 작은 변경사항이 있는 경우에는 마이너 버전넘버를 변경하게 된다.

  1. 버그 픽스와 같이 오류로 인해 내부 코드가 바뀌는 경우
  2. 추가되는 기능이 존재하나 클라이언트의 코드가 변경될 필요는 아닌경우(Optional 파라미터 추가 등)

이렇듯 클라이언트 측의 코드가 변경되지 않아도 되는 상황에서 API의 코드가 수정되는 경우에는  Minor한 버전으로 보면 된다.


어떤 방식으로 관리하면 될까?

버전의 관리방법은 여러가지 방법으로 관리될 수가 있다.

관리방법을 채택했다면 API의 버전관리방식또한 문서를 통해 제공해야한다.

 

API의 버전넘버는 보통 세파트로 구분한다. 예를들어 v1.2.3 이런식으로 말이다.

다만 첫번째 영역의 숫자는 메이저 버전 그리고 두번째, 세번째는 마이너 버전으로 두번째는 기능 추가시 마지막으로 세번째는 버그픽스와 같은경우를 관리하는 버전으로 나뉜다.

 

각 버전별 API가이드 문서는 제공되어야 추후에도 클라이언트가 API를 호출하는데 문제가 없을 것이다.

 

방법1. URI를 이용

URI path에 버전넘버가 존재하여 버전을 관리하는 방식이 있다.

다만 이경우에는 마이너한 버전 넘버는 따로 관리하기가 힘들 수 있다.

@GetMapping(value = "test/v1/{id}/")
public MappingJacksonValue restTestApiV1(@PathVariable int id){...}

@GetMapping(value = "test/v1/{id}/")
public MappingJacksonValue restTestApiV2(@PathVariable int id){...}

방법2. Request Parameter를 이용

간단하게 기존 메서드의 @GetMapping의 값을 변경해주는 방식이 있다.

version을 관리하는 parameter를 추가해주는 것이다.

@GetMapping(value = "test/{id}/", param = "version = 1")
public MappingJacksonValue restTestApiV1(@PathVariable int id){...}

@GetMapping(value = "test/{id}/", param = "version = 2")
public MappingJacksonValue restTestApiV2(@PathVariable int id){...}

방법3. Header를 이용

헤더에 키와 값을 추가하여 관리하는 방식이다.

@GetMapping(value = "test/{id}/", headers = "X-API-VERSION = 1")
public MappingJacksonValue restTestApiV1(@PathVariable int id){...}

@GetMapping(value = "test/{id}/", headers = "X-API-VERSION = 2")
public MappingJacksonValue restTestApiV2(@PathVariable int id){...}

헤더의 키값을 추가하여 해당 키값으로 version을 구분할 수 있다.

방법4. MIME Type를 이용

MIME는 Multipurpose Internet Mail Extension의 약자로 일종의 인코딩 방식으로 해당 방식을 통해서도 버전을 관리할 수 있다.

해당 방식은 현재 Github에서 버전을 관리하는 방식이다.

@GetMapping(value = "test/{id}/", produces = "application/vnd.company.appv1+json")
public MappingJacksonValue restTestApiV1(@PathVariable int id){...}

@GetMapping(value = "test/{id}/", produces = "application/vnd.company.appv2+json")
public MappingJacksonValue restTestApiV2(@PathVariable int id){...}

각 방법들의 특징은?

위 방법들은 나름의 특징들이 있다.

  • URI와 Query String을 이용한 버전관리는 매번 같은데이터를 참조하게 되므로 캐싱을 할수 있는 장점이 있다.
    • 물론 일부 구형 웹브라우저 및 웹 프록시는 URI에 쿼리 문자열을 포함할경우 응답을 캐싱하지 않을 수 있다.
  • header를 이용하거나 mime를 이용할 경우 해당값을을 검사하기위한 로직이 필요하다.

Roy fielding의 말에 따르면 /v1/ 과 같은 버전관리는 api가 그만큼 자주 바뀌지 않으며 해당 방식은 지양하며 다른 미디어타입을 사용할 것을 추천한다.

 

물론 헤더에 버전을 추가하는 것 누군가 해당 버전을 빼갈 수 있지만.... 개인적인 생각으로는 버전정보를 빼간다고 딱히 문제가 될 거 같지는 않아 보인다.

 

즉, 4가지 방식 모두 각각 약간의 문제를 갖고 있으며 완벽한 방법은 없는 것으로 보인다. 

다만 좀더 버전을 관리하기에 효율적인 그리고 명확한 방식을 정해서 클라이언트측에 제공하면 되는 것으로 보인다.


주의할 점은?

그렇다면 버전관리시 주의할점은 없을까?

  • URI에 정보를 노출을 하지 않아야한다.
  • 잘못된 헤더값은 지양한다.
  • API인 만큼 웹에서 실행이 가능해야한다.

위에서 말한 주의할 점들은 보면 방법을 선택하는 과정과 개발하는 과정에서 주의해야할 점이고, 개인적으로 주의할점은 API의 버전별로 정확한 문서를 제공해야할 필요가 있을 것으로 보입니다.