버저닝이란 무엇인가?
버저닝이란?
버저닝 이란 API를 개발하면 시간에 따라 버전이 올라가는 것이 당연하다. 그로인해 새기능이 추가로 인해 변경될수 있다. 새 기술로 변경함에 따라 발견하지 못한 오류들이 갑작스럽게 나타날수있다. 그래서 기존 API를 사용자에게 안정적인 API를 제공하면서 새로운 버전의 API를 함께 제공하며 사용자가 원하는 API의 버전을 선택할수있는 기술을말한다.
다양한 API 버저닝 기법
URL버저닝 - URL에 버전 번호를 붙임
요청 파라미터 버저닝 - 버전 번호를 나타내는 HTTP 요청 파라미터를 추가
커스텀 HTTP 헤더 버저닝 = 버전을 구분할 수 있는 HTTP 요청 헤더를 추가
미디어 타입 버저닝 - 요청에 Accept 헤더를 사용해서 버전을 구분
프로젝트환경
springboot -version : 2.6.3
bulid : gradlejava -version : 11
DB : Mysql_8.0.33
IDE : IntelliJ _Ultimate
POSTMAN
LOMBOK
사전준비
Member1(Entity)
- Long id
- String name
- String category
- int rating
- String description
Member2(Entity)
- Long id
- String name
- String category
- int rating
- String description
- double price <---추가---->
MemberBeRepository(interface)
- extends CrudRepository<Member1,Long>
MemberAfepository(interface)
- extends CrudRepository<Member2,Long>
MemberSeriveImpl
- CRUD 생성
※GET,POST 방식만 사용함
URL 버저닝
UrlV1Controller
@RestController
@RequestMapping("/members/v1")
@RequiredArgsConstructor
public class UrlV1Controller {
private final MemberService memberService; //memberBeRepository
@GetMapping
@ResponseStatus(HttpStatus.OK)
public Iterable<Member1> getAllMembers(){
return memberService.getMember();
}
@PostMapping
@ResponseStatus(HttpStatus.CREATED) //201성공
public Member1 createMember(@Valid @RequestBody Member1 member1){
return memberService.createMember(member1);
}
}
UrlV2Controller
@RestController
@RequestMapping("/members/v2")
@RequiredArgsConstructor
public class UrlV2Controller {
private final MemberAfRepository memberAfRepository;
@GetMapping
@ResponseStatus(HttpStatus.OK)
public Iterable<Member2> getAllMember2(){
return memberAfRepository.findAll();
}
@PostMapping
@ResponseStatus(HttpStatus.CREATED) //201
public Member2 createMember(@Valid @RequestBody Member2 member2){
return memberAfRepository.save(member2);
}
}
두개의 버전 API를 만들고 POSTMAN v1,v2,버전을 post형식으로 추가한후 확인해 보자
( url = http://localhost:8080/members/"v1 or v2")
post 추가
{
"name":"Before Version-v1", //v1 버전
"description":"v1",
"category":"before",
"rating":3
}
{
"name":"After Version-v2", // v2 버전
"description":"v2",
"category":"after",
"price":34.45,
"rating":5
}
GET 조회
HTTP 요청 파리미터
파라미터를 사용한 버저닝 기법을 알아보자
HttpPaController
@RestController
@RequestMapping("/members/")
@RequiredArgsConstructor
public class HttpPaController {
private final MemberService memberService;
private final MemberAfRepository memberAfRepository;
@GetMapping(params = "version=v1")
@ResponseStatus(HttpStatus.OK)
public Iterable<Member1> getV1Member(){
return memberService.getMember();
}
@PostMapping(params = "version=v1")
@ResponseStatus(HttpStatus.CREATED)
public Member1 createV1Member(@Valid @RequestBody Member1 member1){
return memberService.createMember(member1);
}
@GetMapping(params = "version=v2")
@ResponseStatus(HttpStatus.OK)
public Iterable<Member2> getV2Member(){
return memberAfRepository.findAll();
}
@PostMapping(params = "version=v2")
@ResponseStatus(HttpStatus.OK)
public Member2 createV2Member(@Valid @RequestBody Member2 member2){
return memberAfRepository.save(member2);
}
}
postman을 사용해 url은 http://localhost:8080/members/?version="v1 or v2" 를 사용하여 위와 똑같은 값을 사용하여
추가해보자 그럼 결과는 같은 값이 나올것이다.
GET조회
V2
커스텀 HTTP 헤더
헤더를 이용한 방법을 알아보자 이전 파라미터 방식과 비슷하다. param부분을 header로 바꾸고 사용하고싶은 이름을 사용한다.
CostomHeaderController
@RestController
@RequestMapping("/members/")
@RequiredArgsConstructor
public class CustomHeaderController {
private final MemberService memberService;
private final MemberAfRepository memberAfRepository;
@GetMapping(headers = "API-VERSION=v1") //변경
@ResponseStatus(HttpStatus.OK)
public Iterable<Member1> getV1Member(){
return memberService.getMember();
}
@PostMapping(headers = "API-VERSION=v1") //변경
@ResponseStatus(HttpStatus.CREATED)
public Member1 createV1Member(@Valid @RequestBody Member1 member1){
return memberService.createMember(member1);
}
@GetMapping(headers = "API-VERSION=v2") //변경
@ResponseStatus(HttpStatus.OK)
public Iterable<Member2> getV2Member(){
return memberAfRepository.findAll();
}
@PostMapping(headers = "API-VERSION=v2") //변경
@ResponseStatus(HttpStatus.OK)
public Member2 createV2Member(@Valid @RequestBody Member2 member2){
return memberAfRepository.save(member2);
}
}
API만들고 사용할때에는 URL에다가 커스텀명을 적는것이 아니고 헤더에 값을 넣어 보내야한다.
헤더에 값을 넣어 추가하면 이전과 같은 결과를 얻을수 있다.
미디어 타입
미디어 타입을 사용하는 버저닝은 콘텐트 협상 버저닝 또는 Accept Header 버저닝이라고 부른다. 커스텀 HTTP 헤더를 사용하지않고 HTTP 표존 Accept 헤더를 사용한다.
AcceptHeaderController
@RestController
@RequestMapping("/members/")
@RequiredArgsConstructor
public class AcceptHeaderController {
private final MemberService memberService;
private final MemberAfRepository memberAfRepository;
@GetMapping(produces = "application/vnd.test.app-v1+json") //변경
@ResponseStatus(HttpStatus.OK)
public Iterable<Member1> getV1Member(){
return memberService.getMember();
}
@PostMapping(produces = "application/vnd.test.app-v1+json") //변경
@ResponseStatus(HttpStatus.CREATED)
public Member1 createV1Member(@Valid @RequestBody Member1 member1){
return memberService.createMember(member1);
}
@GetMapping(produces = "application/vnd.test.app-v2+json") //변경
@ResponseStatus(HttpStatus.OK)
public Iterable<Member2> getV2Member(){
return memberAfRepository.findAll();
}
@PostMapping(produces = "application/vnd.test.app-v2+json") //변경
@ResponseStatus(HttpStatus.OK)
public Member2 createV2Member(@Valid @RequestBody Member2 member2){
return memberAfRepository.save(member2);
}
}
커스텀 버저닝 처럼 헤더를 따로 보내는것이 아닌 기본적인 Accpet헤더에 넣어서 전송한다.
결론
지금까지 4가지 방법중에 어떤것이 좋은 방법이라고 한다면, 아마도 개발자의 선택인것같다. 어떤거이 더좋다고 할수 없다. 자기 취향의 맞게 사용하는것이 좋을것같다.
'Spring > SpringBoot' 카테고리의 다른 글
[SpringBoot] SSE를 이용한 실시간 알림 구현하기! (0) | 2024.06.13 |
---|---|
[SpringBoot] Custom @Vailid 어노테이션 만들기 (0) | 2024.05.10 |
[Spring-Boot] Srpingdoc OpenApi 스웨거(Swagger) 사용하기 (0) | 2024.04.24 |
[SpringBoot] 스프링 클라우트 볼트(Vault)를 활용하여 정보관리 (1) | 2024.01.04 |
[SpringBoot] JAR(JAVA Archive) 파일 생성 하는법 (0) | 2023.12.08 |