Deprecated 된 rest template를 대체하는 HTTP 클라이언트
블로그에 쓰는 글들은 여기에 있습니다.(정리가 좀 필요할 것 같지만)
https://github.com/YuSunjo/spring-boot-example
feignClient
- interface를 작성하고 기존의 spring boot 처럼 사용해서 복잡도가 낮고 은근 친숙함
- netflix에서 만들어졌다고 하네요.
- 요즘 MSA에서 많이 사용한다고 합니다.
(제대로 해보지 않아서 ㅠ)
import
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:2021.0.0"
}
}
dependencies {
...
// feign client
implementation 'org.springframework.cloud:spring-cloud-starter-openfeign'
implementation group: 'io.github.openfeign', name: 'feign-gson', version: '11.0'
...
}
config
@EnableFeignClients(basePackageClasses = PlatformApplication.class)
@Configuration
public class FeignClientConfig {
}
- EnableFeignClients 저거를 @SpringBootApplication 여기에 해도 상관 없습니다.
controller
@RestController
@RequiredArgsConstructor
public class FeignController {
private final FeignService feignService;
@GetMapping("/feign/ping")
public String pong() {
return feignService.ping();
}
}
service
@Service
@RequiredArgsConstructor
public class FeignService {
private final TestFeignClient testFeignClient;
public String ping() {
return testFeignClient.ping();
}
}
TestFeignClient
@FeignClient(
name = "testFeignClient",
url = "${test.blog_url}",
configuration = FeignClientConfig.class)
public interface TestFeignClient {
@GetMapping(value = "ping", produces = "application/json")
String ping();
}
- test.blog_url은 resources에 application.yml에 설정해주면 됨
나머지 예시들
// 파라미터
@GetMapping(value = "{url}/lecture/{lectureId}", produces = "application/json")
TestResponse test(@PathVariable String url, @PathVariable String lectureId);
// 헤더
@GetMapping(value = "...", produces = "application/json")
TestResponse test(@RequestHeader(HttpHeaders.AUTHORIZATION) String accessToken);
// 쿼리 스트링
@GetMapping(value = "...", produces = "application/json")
TestResponse test(@RequestParam String access_token);
// 바디
@GetMapping(value = "...", produces = "application/json")
TestResponse test(@RequestBody AppleAccessTokenRequest accessTokenRequest);
지금은 간단한 ping 만 가져오는 것을 해봤습니다. (나중에 소셜 로그인 정리할 때 feign client 사용해서 해보겠습니다.)
그 외에 쿼리 스트링, 헤더, 바디 등 넣을 수 있다!!
webClient
- 논블로킹 및 비동기 접근 방식 지원
- 빌더 방식의 인터페이스를 지원하고 리액티브 타입(Mono, Flux)의 전송과 수신을 합니다.
config
@Configuration
public class WebClientConfig {
ExchangeStrategies exchangeStrategies = ExchangeStrategies.builder() .codecs(
configurer -> configurer.defaultCodecs().maxInMemorySize(20 * 1024 * 1024)
).build();
@Bean
public WebClient webClient() {
return WebClient.builder()
.exchangeStrategies(exchangeStrategies)
.clientConnector(new ReactorClientHttpConnector(
HttpClient.create()
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 20000)
.doOnConnected(conn ->
conn.addHandler(new ReadTimeoutHandler(20000, TimeUnit.MILLISECONDS))
)
)).build();
}
}
- 메모리, 타임아웃 등의 처리도 가능
import
// webclient
implementation 'org.springframework.boot:spring-boot-starter-webflux'
controller
@RestController
@RequiredArgsConstructor
public class WebClientController {
private final WebClientService webClientService;
@GetMapping("/webclient/ping")
public String ping() {
return webClientService.ping();
}
}
service
@Service
@RequiredArgsConstructor
public class WebClientService {
private final WebClientApiCaller webClientApiCaller;
public String ping() {
return webClientApiCaller.ping();
}
}
WebClientApiCaller
public interface WebClientApiCaller {
String ping();
}
WebClientApiCallerImpl
@Component
@RequiredArgsConstructor
public class WebClientApiCallerImpl implements WebClientApiCaller {
private final WebClient webClient;
private final Duration timeout = Duration.ofMillis(20000);
@Override
public String ping() {
return webClient
.get()
.uri("<https://api-lovga.site/ping>")
.retrieve()
.onStatus(HttpStatus::is4xxClientError, clientResponse -> Mono.error(new BusinessException(ErrorCode.API_CALLER)))
.onStatus(HttpStatus::is5xxServerError, clientResponse -> Mono.error(new BusinessException(ErrorCode.API_CALLER)))
.bodyToMono(String.class)
.timeout(timeout, Mono.error(new BusinessException(ErrorCode.TIMEOUT_EXCEPTION)))
.block();
}
}
- timeout이 일어났을 경우 커스텀 예외처리 해주고 싶어서 위처럼 처리
이 외에
// 헤더
.headers(headers -> {
headers.add("auth", token);
})
// 바디
.body(BodyInserters.fromFormData(data))
// 쿼리 스트링
.uri(
uriBuilder -> uriBuilder
.queryParam("limit", limit)
.queryParam("page", page)
.build()
)
- 빌더 패턴이여서 체이닝으로 끌고 가면 됩니다.~
근데 webClient를 사용하면서 webClient 빈 생성하지 않고 WebClient.bulder()도 가능하긴 하다. ⇒ 근데 요청을 보낼때마다 생성해줘서 약간 리소스 낭비(?)라고 생각해서 빈주입해서 했습니다.
'spring boot > 기술 적용' 카테고리의 다른 글
Spring boot에 Facade 패턴 적용 (0) | 2022.10.10 |
---|---|
Spring boot에 전략패턴 적용 (0) | 2022.10.10 |
jpa comment를 custom annotation으로 만들기 (0) | 2022.07.20 |
stub, mock, spy 비교 (0) | 2022.07.02 |
converter를 만들지 않고 jpa mysql에서 json 사용하기 (0) | 2022.06.28 |