728x90
Spring 프레임워크가 제공하는 REST Request 엔드포인트
- RestClient - synchronous client with a fluent API.
- WebClient - non-blocking, reactive client with fluent API.
- RestTemplate - synchronous client with template method API.
- HTTP Interface - annotated interface with generated, dynamic proxy implementation.
RestClient
- 가장 최근 추가된 HTTP 클라이언트로, RestTemplate의 불편함 때문에 사용하던 WebClient는 MVC에서 사용하기 위해 block처리를 해줘야하는 번거로움과 쓰지않는 라이브러리를 잔뜩 갖고 있어야하는 불편함 때문에 두 이름은 합친 RestClient로 명명하여 Spring 6.1, Spring Boot 3.2.0 부터 지원하게 되었다.
- 아래는 Spring 프레임워크 공식 git RestTemplate에 적힌 주석이다. https://github.com/spring-projects/spring-framework/blob/main/spring-web/src/main/java/org/springframework/web/client/RestTemplate.java
* <p><strong>NOTE:</strong> As of 6.1, {@link RestClient} offers a more modern
* API for synchronous HTTP access. For asynchronous and streaming scenarios,
* consider the reactive
* {@link org.springframework.web.reactive.function.client.WebClient}.
*
* <p>{@code RestTemplate} and {@code RestClient} share the same infrastructure
* (i.e. {@linkplain ClientHttpRequestFactory request factories}, request
* {@linkplain org.springframework.http.client.ClientHttpRequestInterceptor interceptors} and
* {@linkplain org.springframework.http.client.ClientHttpRequestInitializer initializers},
* {@linkplain HttpMessageConverter message converters},
* etc.), so any improvements made therein are shared as well.
* However, {@code RestClient} is the focus for new higher-level features.
- 대충 해석하면 이제 이것보다 더 모던한 RestClient 가 배포되었으니 그것을 사용할 것을 권유하고 앞으로 발전은 RestClient가 중점일 것이라한다. 그러므로 우리는 이제 RestTemplate 말고 RestClient 를 사용하자!
- 또한 RestClient를 동기식 HTTP이고 비동기식이면 WebClient를 사용하라고 말한다.
생성
RestClient defaultClient = RestClient.create();
RestClient customClient = RestClient.builder()
.requestFactory(new HttpComponentsClientHttpRequestFactory())
.messageConverters(converters -> converters.add(new MyCustomMessageConverter()))
.baseUrl("<https://example.com>")
.defaultUriVariables(Map.of("variable", "foo"))
.defaultHeader("My-Header", "Foo")
.requestInterceptor(myCustomInterceptor)
.requestInitializer(myCustomInitializer)
.build();
- RestClient가 자체 지원하는 create를 사용할 수도 있고 builder를 사용해 직접 커스텀할 수도 있다.
GET
ResponseEntity result = restClient.get()
.uri("<https://example.com>")
.retrieve()
.toEntity(String.class);
System.out.println("Response status: " + result.getStatusCode());
System.out.println("Response headers: " + result.getHeaders());
System.out.println("Contents: " + result.getBody());
- restClient.get():
- restClient는 WebClient 객체입니다. 이 객체는 HTTP 요청을 보내기 위해 사용됩니다.
- .get() 메서드는 HTTP GET 요청을 보낼 것을 지정합니다.
- .uri("<https://example.com>"):
- 요청을 보낼 URI(여기서는 "https://example.com")를 지정합니다.
- .retrieve():
- 이 메서드는 요청을 실행하고, 응답을 받아오는 작업을 처리합니다.
- 응답은 이 메서드 체인에서 이어지는 메서드(toEntity)로 전달됩니다.
- .toEntity(String.class):
- 응답을 ResponseEntity<String> 타입으로 변환합니다. String.class는 응답 본문을 문자열로 변환할 것을 지정합니다.
- 이 메서드는 전체 HTTP 응답(상태 코드, 헤더, 본문)을 캡슐화하는 ResponseEntity 객체를 반환합니다.
- result 변수는 이 ResponseEntity<String> 객체를 가리킵니다.
POST
Pet pet = ...
ResponseEntity response = restClient.post()
.uri("<https://petclinic.example.com/pets/new>")
.contentType(APPLICATION_JSON)
.body(pet)
.retrieve()
.toBodilessEntity();
- restClient.post():
- restClient는 WebClient 객체입니다. 이 객체는 HTTP 요청을 보낼 때 사용됩니다.
- .post() 메서드는 HTTP POST 요청을 보낼 것을 지정합니다.
- .uri("<https://petclinic.example.com/pets/new>"):
- 요청을 보낼 URI를 지정합니다. 여기서는 "https://petclinic.example.com/pets/new" URL로 POST 요청을 보냅니다. 이 URL은 새로운 애완동물을 추가하는 API 엔드포인트로 가정됩니다.
- .contentType(APPLICATION_JSON):
- 요청의 콘텐츠 타입을 application/json으로 설정합니다. 이것은 Pet 객체가 JSON 형식으로 직렬화되어 전송된다는 것을 의미합니다.
- .body(pet):
- Pet 객체를 요청 본문으로 설정합니다. 이 객체는 JSON으로 변환되어 요청의 본문에 포함됩니다.
- .retrieve():
- 이 메서드는 요청을 실제로 실행하고, 응답을 받아오는 작업을 처리합니다.
- 응답은 이 메서드 체인에서 이어지는 메서드(toBodilessEntity)로 전달됩니다.
- .toBodilessEntity():
- 이 메서드는 ResponseEntity<Void> 타입으로 응답을 반환합니다. 여기서 Void는 응답 본문이 없음을 나타냅니다.
- response 변수는 이 ResponseEntity<Void> 객체를 가리킵니다.
오류 처리
기본적으로 4xx, 5xx 일 때 하위 클래스를 throw 하며 이 동작을 재정의 할 수 있다.
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.get():
- restClient는 WebClient 객체로, HTTP 요청을 보내는 데 사용됩니다.
- .get() 메서드는 HTTP GET 요청을 보낼 것을 지정합니다.
- .uri("<https://example.com/this-url-does-not-exist>"):
- 요청을 보낼 URI를 지정합니다. 여기서는 https://example.com/this-url-does-not-exist라는 URL로 GET 요청을 보냅니다.
- 이 URI는 존재하지 않는 경로를 나타내므로, 404 같은 4xx 오류가 발생할 가능성이 큽니다.
- .retrieve():
- 이 메서드는 요청을 실제로 실행하고, 응답을 받아오는 작업을 처리합니다.
- 응답은 이 메서드 체인에서 이어지는 메서드(onStatus, body)로 전달됩니다.
- .onStatus(HttpStatusCode::is4xxClientError, (request, response) -> { ... }):
- 이 메서드는 특정 상태 코드에 따라 응답을 처리할 수 있도록 합니다.
- HttpStatusCode::is4xxClientError는 4xx 상태 코드(클라이언트 오류)일 경우를 나타냅니다.
- (request, response) -> { ... }는 상태 코드가 4xx일 경우 실행될 람다 함수입니다.
- 이 람다 함수는 MyCustomRuntimeException 예외를 발생시킵니다. 예외는 응답의 상태 코드와 헤더를 인자로 전달받습니다.
- .body(String.class):
- 이 메서드는 응답 본문을 String으로 변환하여 반환합니다.
- 만약 4xx 오류가 발생하지 않으면, 정상적으로 응답 본문이 문자열로 반환되어 result 변수에 저장됩니다.
- 4xx 오류가 발생하면 예외가 발생하고, 이 메서드 호출은 그 이전에 중단됩니다.
예외 처리
- MyCustomRuntimeException:
- 이 예외는 응답의 상태 코드와 헤더 정보를 포함한 사용자 정의 런타임 예외입니다.
- 만약 서버가 4xx 상태 코드를 반환하면, MyCustomRuntimeException이 발생하여 오류 상태를 처리합니다.
- MyCustomRuntimeException 를 정의하여 커스텀 예외처리가 가능합니다.
'Dev > Spring Boot' 카테고리의 다른 글
Spring Boot JPA - BufferedReader로 CSV 파일을 읽어 DB에 저장하기 (1) | 2024.09.20 |
---|---|
Spring Boot - RestClient 로 공공데이터 얻어오기 (0) | 2024.08.20 |
Java - Stream 으로 코드 최적화 (0) | 2024.07.17 |
Servlet - HttpServlet 사용법 (Request , Response) (0) | 2024.06.04 |
Spring 기초 1) WAS란 무엇인가? (0) | 2024.04.18 |