[Dev] 서버 클라이언트 사이 버전을 관리하는 방법
🍎 상황 설명
- 서비스 리뉴얼의 기반이 아직 완전히 준비되지 않은 상황 (예: 사용자 DB 설계, 인증 시스템)에서 요구사항 할당
- 현재 제공 중인 서비스를 유지하면서도 사용자에게 새로운 기능을 제공해야 하므로, 레거시 시스템을 기반으로 API를 개발.
- 서비스의 기반이 완성된 이후, 개발팀 내부 의견 조율을 거쳐 기존 기능을 개선하고 리팩터링 하기로 결정.
- 결과적으로, 레거시 버전과 개선된 버전을 어떻게 관리할 것인가에 대한 문제를 인식하게 됨.
🤔 버전관리를 문제로 인식한 이유
- 한 번 정해지고 서비스에 반영이 된다면 되돌리기 매우 어렵기 때문입니다.
- 리소스로 버전을 관리한다고 가정해 보겠습니다.
- 리소스로 버전을 관리하고자 정했으니 클라이언트에서 서버에 요청을 보낼 때 반드시 두 개의 EndPoint가 필요합니다.
- 레거시 버전 EndPoint : "/example/legacy"
- 개선 후 버전 EndPoint : "/example"
❓ 위와 같이 EndPoint를 정하고 사용자에게 배포했다면 개선이 완료된 후에 Controller에 존재하는 레거시 버전 EndPoint를 제거할 수 있을까요?
- 그렇지 않습니다❌. 사용자들 중 강제 업데이트를 하지 않은 이상 예전의 버전을 사용하고 있는 고객도 있을 테니까요
🍎 세 가지 버전 관리 그리고 Trade-Off
세 가지 방법의 버전 관리 방법을 알아보고 각 방법의 장단점을 알아봅니다.
🍏 Query Parameter
Query Parameter를 사용한 버전 관리의 예시 :
https://example.com/sample?version=legacy
- 장점
- 버전 정보가 파라미터 안으로 들어가 있어 기존 URL을 유지하면서 버전 정보를 추가할 수 있습니다.
- Path Parameter 보다 상대적으로 손쉽게 버전을 변경할 수 있습니다.
- 동일한 리소스를 재사용함으로 하나의 EndPoint로 여러 버전을 관리할 수 있습니다.
- 단점
- 하나의 EndPoint로 여러 버전을 관리할 수 있다는 것은 장점임과 동시에 단점 일 수 있습니다. 서버에서 요청을 받아 Query String에 따른 버전을 구별해 버전마다 서비스와 모델을 관리해야 한다면 코드 입장에서 복잡도가 늘 수 있습니다.
🍏 Path Parameter
Path Parameter를 사용한 버전 관리 예시 :
https://example.com/v1 or https://example.com/v2
- 장점
- 명확한 버전 명시로 어떤 버전의 EndPoint를 사용하는지 알 수 있고 직관적이기 때문에 문서화 시 가독성을 높일 수 있습니다.
- 경로가 명확하기 때문에 버전을 구분하면 로드 밸런서를 통해 버전별로 처리 규칙을 설정하는 것이 간편합니다.
- 단점
- 코드 레벨에서 분기가 일어나는 것이 아닌 인프라 레벨에서 분기가 발생함으로 관리 포인트가 늘어납니다.
🍏 Header
Header를 사용한 버전 관리 예시 :
Http Header 내부에 Custom Key : Value로 존재. e.g) version_manage: v1
- 장점
- 상대적으로 Query Parameter, Path Parameter에 포함하지 않아 EndPoint 구조를 더 깔끔하고 간결하게 유지할 수 있습니다.
- 단점
- 웹 엔진이나 프락시 서버는 특정 헤더에 대한 보안, 성능, 표준 준수 등의 이유로 Custom Header를 허용하지 않을 수 있습니다.
- 예를 들어, NginX를 사용하고 있다면 Custom Header 설정에 주의해야 합니다. underscore가 포함된 사용자 Header가 존재한다면 누락될 수 있습니다.(링크) 만약 Header가 누락되었다면 Controller에서 값을 받을 수 없을 것이고 이는 기대하는 결과 값을 사용자에게 전달하지 못할 수 있습니다.
🍎 정리
- 세 가지 버전 관리 방법의 장단점을 살펴보았습니다. 이와 관련하여 중요한 질문은 “어떤 상황에서 어떤 방법을 선택해야 할까? “입니다.
- 신뢰구간 통신에서는 Header를 사용하고, 비신뢰구간 통신에서는 상황에 맞춰 Query Parameter 또는 Path Parameter를 사용하는 것을 제안합니다.
- 업무 경험을 바탕으로 말씀드리자면, Legacy와 개선된 버전을 구분할 때는 작은 범위에서 Query Parameter를 사용했고 프로젝트의 변경사항이 크고 큰 범위에서 버전 관리가 필요할 때는 Path Parameter 방식을 채택해 문제를 해결했습니다.
- 각 조직의 환경과 자원은 다르기 때문에 특정한 방법이 절대적으로 맞다고 할 수는 없습니다. 그러나 상황에 따라 최적의 방법은 존재한다고 생각합니다.
p.s) 🍏 이 글이 업무에 도움이 되었으면 좋겠습니다.
📚 참고 자료
Nginx에서 애플리케이션으로 Request Header 전달하기