[# New in Spring 6.1: RestClient](https://spring.io/blog/2023/07/13/new-in-spring-6-1-restclient/)
[# REST Clients](https://docs.spring.io/spring-framework/reference/integration/rest-clients.html)
## Test코드 작성하듯 호출하고 싶다
```
mockMvc.perform(get("/api/posts")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(condition)))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.length()", equalTo(1)));
```
[!NOTE] fluent API
설계가 메서드 체인에 광범위하게 의존하는 객체지향 api이다. fluent api는 DSL(domain specific language)을 만들어 코드 가독성을 높이는데 그 목적이 있다.
```
Author author = AUTHOR.as("author");
create.selectFrom(author)
.where(exists(selectOne()
.from(BOOK)
.where(BOOK.STATUS.eq(BOOK_STATUS.SOLD_OUT))
.and(BOOK.AUTHOR_ID.eq(author.ID))));
```
- RestTemplate과 비교
- [### Migrating from `RestTemplate` to `RestClient`](https://docs.spring.io/spring-framework/reference/integration/rest-clients.html#_migrating_from_resttemplate_to_restclient)
```
restTemplate.postForObject(URI, Object, Class)
restClient.post()
.uri(String, Object...)
.body(Object)
.retrieve()
```
참고영상 : [빌더와 lombok](https://youtu.be/rKpCtQL-C08)
[!NOTE] spring에서 제공하는 4가지 REST endpoints
- 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 생성하기
- create() 메서드를 이용한 방법
```
RestClient defaultClient = RestClient.create();
```
- builder를 이용한 방법
```java
@Bean
RestClient restClient(RestClient.Builder builder) {
return builder
.requestFactory(new JdkClientHttpRequestFactory())
.messageConverters(converters ->
converters.add(new MyCustomMessageConverter()))
.baseUrl("https://example.com")
.defaultUriVariables(Map.of("variable", "foo"))
.defaultHeader("My-Header", "Foo")
.requestInterceptor(myCustomInterceptor)
.requestInitializer(myCustomInitializer)
.build();
}
```
[!NOTE] client request factory : HttpClient
- JdkClientHttpRequestFactory : jdk에서 제공 [java.net.http.HttpClient](https://docs.oracle.com/en/java/javase/17/docs/api/java.net.http/java/net/http/HttpClient.html),
- HttpComponentsClientHttpRequestFactory : 톰켓에서 제공
- JettyClientHttpRequestFactory : 제티에서 제공
- ReactorNettyClientRequestFactory : 네띠에서 제공
## RestClient 사용하기
```
restClient.get()
.uri("https://example.com")
.retrieve()
.body(String.class);
```
- header가 필요하면 header(string, string) 넣어주면 됨. header관련 메서드도 존재
- get, post, put, delete 등 다 지원
- retrieve() 호출하면 응답 받음
```
ResponseEntity<Void> response = restClient.post()
.uri("https://petclinic.example.com/pets/new")
.contentType(APPLICATION_JSON)
.body(pet)
.retrieve()
.toBodilessEntity();
```
- retrieve() body에 담아서 호출
- 아래는 에러처리
```
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);
```
- 아래는 응답을 다르게 주는 exchange() 예제
```
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; } });
```
## HTTP Interface : @HttpExchange
- 예제는 조금 이따 봅시다
- https://github.com/ohhoonim/lms.git
- `http://jsonplaceholder.typicode.com/posts/1/comments/`
- 어짜피 배운거니 가상스레드 옵션 켜주자(jdk 21이상)
```
# application.properties
spring.threads.vitual.enabled=true
```
- 아래 예제처럼 인터페이스만 선언해주면 위에 처럼 일일히 구현할 필요없음.
```
@HttpExchange
interface RepositoryService {
@GetExchange("/repos/{owner}/{repo}")
Repository getRepository(@PathVariable String owner, @PathVariable String repo);
}
```
- 단, 빈 등록을 미리 해주어야함. 언젠가는 자동 생성해주겠지만, 아래이슈보면 이미 만들고들 있음.
- https://github.com/spring-projects/spring-boot/issues/31337
```
@Bean
RepositoryService repositoryProxy(RestClient.Builder builder) {
RestClient restClient = builder.baseUrl("https://api.github.com/").build();
RestClientAdapter adapter = RestClientAdapter.create(restClient);
HttpServiceProxyFactory factory =
HttpServiceProxyFactory.builderFor(adapter).build();
return factory.createClient(RepositoryService.class);
}
```
- 사용할 수 있는 parameter
- [Method Parameters](https://docs.spring.io/spring-framework/reference/integration/rest-clients.html#rest-http-interface-method-parameters)
- 응답 객체는 다음과 같음
- void
- HttpHeaders
- <T>
- ResponseEntity<Void>
- ResponseEntity<T>
댓글
댓글 쓰기