Table of Contents
Feign Client
Rest API 호출과 Json 을 클래스로 자동변환까지 해주는 라이브러리이다.
의존성
dependencies {
implementation 'org.springframework.cloud:spring-cloud-openfeign-core:3.1.5'
implementation 'org.springframework.cloud:spring-cloud-starter-openfeign:3.1.5'
# compile("org.springframework.cloud:spring-cloud-starter-openfeign")
}
활성화
@EnableFeignClients
@SpringBootApplication
public class HelloApplication {
public static void main(String[] args) {
SpringApplication.run(HelloApplication.class, args);
}
}
설정
public class FeignClientConfig implements Jackson2ObjectMapperBuilderCustomizer {
private static final Logger log = LoggerFactory.getLogger(FeignClientConfig.class);
public FeignClientConfig() {
}
@Bean
public FeignFormatterRegistrar localDateFeignFormatterRegister() {
return (registry) -> {
DateTimeFormatterRegistrar registrar = new DateTimeFormatterRegistrar();
registrar.setUseIsoFormat(true);
registrar.registerFormatters(registry);
};
}
@Bean
public FeignErrorDecoder decoder() {
return new FeignErrorDecoder();
}
public void customize(Jackson2ObjectMapperBuilder jacksonObjectMapperBuilder) {
jacksonObjectMapperBuilder
.featuresToEnable(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL)
.featuresToDisable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
.timeZone(TimeZone.getDefault())
.modulesToInstall(new Module[]{new JavaTimeModule()})
.locale(Locale.getDefault()).simpleDateFormat("yyyy-MM-dd HH:mm:ss");
}
}
public class FeignRetryConfig {
@Value("${feign.retry.period}")
private long period;
@Value("${feign.retry.max-period}")
private long maxPeriod;
@Value("${feign.retry.max-attempt}")
private int maxAttempt;
public FeignRetryConfig() {
}
@Bean
public Retryer retryer() {
return new Retryer.Default(this.period, this.maxPeriod, this.maxAttempt);
}
}
public class FeignErrorDecoder implements ErrorDecoder {
@Override
public Exception decode(String methodKey, Response response) {
switch (response.status()){
case 400:
break;
case 404:
if(methodKey.contains("getOrders")){
return new ResponseStatusException(HttpStatus.valueOf(response.status()),
"User's orders is empty.");
}
break;
default:
return new Exception(response.reason());
}
return null;
}
}
서비스
@FeignClient(name = "HELLO-SERVICE",configuration = {FeignClientConfig.class, FeignRetryConfig.class})
public interface HelloService {
@GetMapping("/hello/{itemId}")
HelloModel getHelloByItemId(@PathVariable("itemId") String itemId);
@PostMapping("/hello/basic")
ProductDetailBasicResponseModel fetchHello(
@RequestBody List<ItemidOnlyDto> req
);
}
Header 붙이기
특정 메소드에만 붙이기
@FeignClient(name = "HELLO-SERVICE",configuration = {FeignClientConfig.class, FeignRetryConfig.class})
public interface HelloService {
@GetMapping("/hello/{itemId}")
HelloModel getHelloByItemId(@PathVariable("itemId") String itemId);
@PostMapping("/hello/basic")
ProductDetailBasicResponseModel fetchHello(
@RequestHeader("X-Auth-Token") String accessToken,
@RequestBody List<ItemidOnlyDto> req
);
}
모든 메소드에 붙이기
RequestInterceptor
를 구현해 줌으로 해서,
모든 Feign Client method 에 header 가 자동으로 붙는다.
@Component
public class FeignRequestInterceptor implements RequestInterceptor {
private static final String X_AUTH_TOKEN = "X-Auth-Token";
@Override
public void apply(RequestTemplate requestTemplate) {
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (requestAttributes == null) {
return;
}
HttpServletRequest request = requestAttributes.getRequest();
LoginInfo loginInfo = (LoginInfo) request.getAttribute("loginInfo");
if (loginInfo == null) {
return;
}
requestTemplate.header(X_AUTH_TOKEN, loginInfo.getBrowser());
}
}
후기
첨 JPA 접했을 때,
명령 하나 호출하면,
지 혼자 쿼리 작성해서 호출하고 리턴값 받아서 엔터티에 채워주고…
신기했는데…
딱 그느낌이다.
명령 하나 호출하면,
지 혼자 RequestBody 생성해서 url 호출하고,
리턴 json 받아서 response class 에 매핑까지 해준다.
심지어 서버가 죽어 있으면 retry 까지도 해준다.
더군다나,
learning curve 라는 단어 쓰는게 민망할 정도로 쉽다.
헐…
(머리가 나쁘면 손가락이 고생한다.)
@Headers(“X-Auth-Token: {access_token}”)
@RequestLine(“GET /orders/{id}”)
Order get(@Param(“id”) String id, @Param(“access_token”) String accessToken);
https://www.baeldung.com/java-feign-request-headers