모놀리스 아키텍처(모든서비스가 한프로젝트로 통합되어있는형태)의 서비스는 규모가 커질수록 하나로 통합되어있는 특성때문에 sideEffect를 고려하지 않을수없다. 최근에는 MSA(마이크로서비스 아키텍처 : 작은 단위의 여러프로젝트등의 상호작용으로 서비스하는형태)등 으로 서비스마다 각각 다른서버를 사용하여 서비스 하는형태가 늘었다. 각 서버는 필요한 서버의 API를 활용하여 서비스하며 이과정에서 스프링에서는 Rest template 와 webclient 를 통하여 다른 서버와 요청을 주고받을수 있도록 도와준다.
RestTemplate
pring에서 지원하는 객체로 간편하게 Rest 방식 API를 호출할 수 있는 Spring 내장 클래스이다. Spring 3.0부터 지원되었고, json, xml 응답을 모두 받을 수 있다.
Rest API 서비스를 요청 후 응답받을 수 있도록 설계되어 있으며 HTTP 프로토콜의 메소드(ex. GET, POST, DELETE, PUT)들에 적합한 여러 메소드를 제공한다.
WebClient
Spring Framework 5부터는 WebFlux 스택과 함께 Spring은 WebClient라는 새로운 HTTP 클라이언트를 도입하여 기존의 동기식 API를 제공할 뿐만 아니라 효율적인 비차단 및 비동기 접근 방식을 지원하여, Spring 5.0 이후부터는 RestTemplate는 deprecated 되었다.
//RestTemplate GET example
public String getName() {
URI uri = UriComponentsBuilder
.fromUriString("http://localhost:9090")
.path("/api/v1/crud-api")
.encode()
.build()
.toUri();
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> responseEntity = restTemplate.getForEntity(uri, String.class);
return responseEntity.getBody();
}
public String getNameWithPathVariable() { //path variable 이 있는경우
URI uri = UriComponentsBuilder
.fromUriString("http://localhost:9090") // 외부 api 주소
.path("/api/v1/crud-api/{name}") // -> 외부 api의 endpoint
.encode()
.build()
.expand("name") // 복수의 값을 넣어야할 경우 , 를 추가 위의경우 pathVariable 의 값이들어감
.toUri();
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> responseEntity = restTemplate.getForEntity(uri, String.class); //해당 uri 에대한 응답값을 String 로 받음
return responseEntity.getBody();
}
public String getNameWithParameter(String name) { //파라미터를 넣는경우
URI uri = UriComponentsBuilder
.fromUriString("http://localhost:9090")
.path("/api/v1/crud-api/param")
.queryParam("name", name) //=> 외부 api 호출시 name이라는 parameter를 추가함 위의경우
//http://localhost:9090/api/v1/crud-api/param?name={name} 과 같이 호출됨
.encode()
.build()
.toUri();
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> responseEntity = restTemplate.getForEntity(uri, String.class);
return responseEntity.getBody();
}
//Rest template post의 경우
public ResponseEntity<MemberDto> postWithParamAndBody() {
URI uri = UriComponentsBuilder
.fromUriString("http://localhost:9090")
.path("/api/v1/crud-api")
.encode()
.build()
.toUri();
MemberDto memberDto = new MemberDto();
memberDto.setName("flature!!");
memberDto.setEmail("flature@gmail.com");
memberDto.setOrganization("Around Hub Studio");
RestTemplate restTemplate = new RestTemplate();
return restTemplate.postForEntity(uri, memberDto,
MemberDto.class); // 외부 api에 post 요청을 보내되 request Body로 memeberDto를 첨부하여 호출함 응답값은 MemberDto의 형태로받을거라는 명시
}
//WebClient get
public String getNameWithPathVariable() {
WebClient webClient = WebClient.create("http://localhost:9090"); -> 외부 api서버
ResponseEntity<String> responseEntity = webClient.get()
.uri("/api/v1/crud-api/{name}", "Flature") //-> 외부 api의 end포인트 와 pathVariable
.retrieve()
.toEntity(String.class)
.block();
return responseEntity.getBody();
}
//webClient post
public ResponseEntity<MemberDto> postWithParamAndBody() {
WebClient webClient = WebClient.builder()
.baseUrl("http://localhost:9090")
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)// 기본 해더
.build();
MemberDto memberDTO = new MemberDto();
memberDTO.setName("flature!!");
memberDTO.setEmail("flature@gmail.com");
memberDTO.setOrganization("Around Hub Studio");
return webClient.post().uri(uriBuilder -> uriBuilder.path("/api/v1/crud-api").build())
.bodyValue(memberDTO) // body를 통해 memberDto라는 파라미터를 넘김
.retrieve()
.toEntity(MemberDto.class)
.block();
}
- 스프링(스프링부트) 에서는 서버간 통신이 필요할때 스프링 자체에서 webClient와, RestTemplate를 제공하며 이를 통해 보다 편하게 서버간 통신을 구현할 수 있다.
- RestTemplate는 depreacate 되었으나 기존 사용하던 프로젝트를 유지보수할 일이생길 수 있기에 어느정도 이해가 필요하다.
- 위 글에서는 Blocking 한방법에 대해서 예제코드로 다루었다. webClient의 핵심인 비동기 방법과 RestTemplate 의 차이에 대해서는 다른글을통해 정리해야 할것같다. 😅