
spring-learning-test 과제를 진행하는 마지막 주가 시작되었다!
이번주는 http-client와 auth에 대해서 배운다!
이번 과제에선 RestClient, RestTemplate 등 여러 http client들을 사용해본다!
프로젝트 진행할 때는 OpenFeign만 사용해봤는데, 이번 기회에 다른 client들을 사용해볼 수 있어서 좋았다.
String fooResourceUrl = "http://localhost:8080/spring-rest/foos";
Foo foo = restTemplate.getForObject(fooResourceUrl + "/1", Foo.class);
ResponseEntity<String> response = restTemplate.getForEntity(fooResourceUrl + "/1", String.class);
Get 요청은 예시 코드와 같이 getForObject를 통해, 요청을 보내고 응답 받아 객체에 매핑할 수 있다.
응답의 상태코드, 헤더를 받고 싶으면, getForEntity를 사용해 ResponseEntity를 응답으로 받을 수 있다.
다른 Http 메소드들에 대한 함수도 제공한다.
public <T> ResponseEntity<T> exchange(
String url,
HttpMethod method,
@Nullable HttpEntity<?> requestEntity,
Class<T> responseType,
Object... uriVariables
);
ResponseEntity<String> response = restTemplate.exchange(
"https://jsonplaceholder.typicode.com/todos/1",
HttpMethod.GET,
request,
String.class
);
exchange()를 사용하면, 다양한 HTTP 메소드를 지원하고, 요청과 응답을 세밀하게 제어할 수 있다!
@Component
public class RestTemplateResponseErrorHandler implements ResponseErrorHandler {
@Override
public boolean hasError(ClientHttpResponse httpResponse) throws IOException {
return httpResponse.getStatusCode().is5xxServerError() ||
httpResponse.getStatusCode().is4xxClientError();
}
@Override
public void handleError(ClientHttpResponse httpResponse) throws IOException {
if (httpResponse.getStatusCode().is5xxServerError()) {
//Handle SERVER_ERROR
throw new HttpClientErrorException(httpResponse.getStatusCode());
} else if (httpResponse.getStatusCode().is4xxClientError()) {
//Handle CLIENT_ERROR
if (httpResponse.getStatusCode() == HttpStatus.NOT_FOUND) {
throw new NotFoundException();
}
}
}
}
RestTemplate에서 예외 처리 하려면, 위와 같이 ResponseErrorHandler를 구현해준다.
Pet pet = restClient.get()
.uri("https://petclinic.example.com/pets/{id}", id)
.accept(APPLICATION_JSON)
.retrieve()
.body(Pet.class)
ResponseEntity<String> result = restClient.get()
.uri("https://example.com")
.retrieve()
.toEntity(String.class);
Get 요청은 위와 같이 보낼 수 있다.
체인 방식으로 작성한다.
Pet result = restClient.get()
.uri("https://petclinic.example.com/pets/{id}", id)
.accept(APPLICATION_JSON)
.exchange((request, response) -> {
if (response.getStatusCode().is4xxClientError()) {
throw new MyCustomRuntimeException(response.getStatusCode(), response.getHeaders());
}
else {
Pet pet = convertResponse(response);
return pet;
}
});
RestClient에서도 exchange()를 통해, 요청과 응답을 세밀하게 제어할 수 있다.
String result = restClient.get()
.uri("https://example.com/this-url-does-not-exist")
.retrieve()
.onStatus(HttpStatusCode::is4xxClientError, (request, response) -> {
throw new MyCustomRuntimeException(response.getStatusCode(), response.getHeaders());
})
.body(String.class);
RestClient에서는 .onStatus를 통해, 예외처리를 할 수 있다.
public List<Todo> getTodos() {
return restClient.get()
.uri("/todos")
.retrieve()
.body(new ParameterizedTypeReference<List<Todo>>(){});
}
과제에서 나온 예시인데, Collection을 매핑할 때는 ParameterizedTypeReference<>를 사용해야 했다.
총 5개의 옵션이 있다.
1. RestTemplate
2. WebClient
3. RestClient
4. HttpInterface
5. OpenFeign
각각에 대한 개념과 장단점을 알아보자.