BackEnd/Spring

[Spring] Feign Client 적용기

샤아이인 2022. 12. 20.

개인 프로젝트를 수행하던 도중 Kakao에 위경도를 전달하여 주소로 변환해야 하는 과정이 필요했다.

 

 

맨 처음에는 RestTemplate를 생각했지만, deprecated 되었다고 한다.

따라서 WebFlux의 WebClient 사용을 권장하고 있지만, 사실 우리의 애플리케이션에서는 비동기 처리가 필요 없다 생각되었다.

 

https://stackoverflow.com/questions/47974757/webclient-vs-resttemplate

 

WebClient vs RestTemplate

As per spring 5: WebClient is an interface representing the main entry point for performing web requests. It has been created as a part of the Spring Web Reactive module and will be replacing the

stackoverflow.com

 

따라서 이에 대한 대용으로 사용되는 Netfilx의 FeignClient를 우리의 프로젝트에 적용시켜볼까 한다.

 

1. Feign Client란?

Feign Client란 Netflix에서 개발한 Http Client다.

(HttpClient는 Http 요청을 간편하게 만들어서 보낼 수 있도록 돕는 객체라고 생각하면 될 것 같다.)

처음에는 Netflix에서 자체적으로 개발을 진행했지만 현재는 오픈소스로 전환했으며 SpringCloud 프레임워크의 프로젝트 중 하나로 들어가 있다.

1 - 1) 장점

  • SpringMvc에서 제공되는 어노테이션을 그대로 사용할 수 있다.(Spring Cloud의 starter-openfeign을 사용할 경우)
  • RestTemplate 보다 간편하게 사용할 수 있으며 가독성이 좋다.
  • Feign Client를 사용한 통합 테스트가 비교적 간편하다. (테스트가 편하다는 점은 진짜 장점인 것 같다)
  • 요청에 대한 커스텀이 간편하다.
    • ex) 요청이 실패했을 때 몇 초 간격으로 몇 번 재요청을 보낼 것인지를 구체적으로 정할 수 있다.

1 - 2) 단점

  • 동기적으로 동작한다. 즉, 하나의 요청이 끝나야 다음 동작이 가능하다.

하지만 우리 술술 정도의 애플리케이션은 사실상 동기 처리로 충분하다 생각되었다.

 

참고해볼만한 우아한 형제들의 코드

https://github.com/woowabros/feign-apply-experience-sample

 

GitHub - woowabros/feign-apply-experience-sample

Contribute to woowabros/feign-apply-experience-sample development by creating an account on GitHub.

github.com

 

2. 의존성 추가

implementation 'org.springframework.cloud:spring-cloud-starter-openfeign:3.1.3'

이거 말고 진자 딱 FeignClient만 의존성을 추가하는 방식도 있기는 한데, 보통 starter들이 더 간편하니... 

이걸 사용하도록 하자 ㅎㅎ

 

3. Main에 애너테이션 추가해주기

@EnableFeignClients // 추가된 부분
@SpringBootApplication
public class SoolsulServerApplication {

    public static void main(String[]args) {
        SpringApplication.run(SoolsulServerApplication.class,args);
    }

}

 

메인 애플리케이션 위에 @EnableFeignClients를 추가해주면 된다!

 

위 애너테이션에서 처리하는 방식을 다음과 같이 수동으로 할 수도 있다고 한다. (슬쩍 살펴만 보자 ㅎㅎ)

7. Declarative REST Client: Feign

 

7. Declarative REST Client: Feign

Feign is a declarative web service client. It makes writing web service clients easier. To use Feign create an interface and annotate it. It has pluggable annotation support including Feign annotations and JAX-RS annotations. Feign also supports pluggable

cloud.spring.io

 

4. API 호출을 담당할 클라이언트 인터페이스를 만들기

클라이언트를 인터페이스로 만들고 내부에 호출할 메서드만 작성하면 된다. 생각보다 간편하다.

인터페이스만 작성해주면 된다는 점에서 편리한 것 같다. 또한 기존의 Spring의 에너테이션들을 사용할 수 있다.

 

4 - 1) 예시 코드

// name: FeignClient의 이름을 설정한다.
// url="${...}": yml에 설정되어 있는 URL 정보를 불러온다. 
// (@FeignClient 어노테이션 내 url로 설정한 URL로 API를 쏜다.)
@FeignClient(name="test-api", url="${external-api.test.api-url}")
public interface TestFeignClient {

	  // headers: Request Header에 포함 할 정보를 추가 (yml 에서 불러옴)
    @PostMapping(
        value = "/rest/test", 
        headers = "Authorization=${external-api.test.authorization}"
    )
    xxxResponse test(final xxxRequest request); 
    // Request DTO 와 Response DTO는 송/수신 형식 및 타입에 맞게 설정한다.
}
  • @FeignClient : 앱이 런타임 시 해당 어노테이션이 붙은 인터페이스를 토대로 실제 구현체를 만든다.
    • name : 실제 구현체가 Application Context에 빈으로 등록될 때 이름으로 사용된다.
    • url : 요청을 보낼 엔드포인트를 의미한다.
  • @PostMapping : 해당 HttpMethod로 요청을 전송한다.
  • @RequestParam : 요청 시 함께 보낼 파라미터들 설정한다.
    • 메서드의 파라미터에 @RequestParam@RequestHeader 등의 어노테이션을 사용하지 않으면 기본적으로 요청의 Body에 파라미터의 값들이 들어간다.

applicaion.yml

# Feign Client Settings
feign:
  client:
    config:
      test-api:						# Feign Client 명
        decode404:falseloggerLevel: full
        connect-timeout: 3000
        readTimeout: 60000

external-api:
  test:
    api-url: '<https://xxx.yyy.com>'
    authorization: 'ABC'

Request Header Authorization:ABC

POST : https://xxx.yyy.com/rest/test 로 API가 요청된다.

 

4 - 2) Feign을 통해 GET Request 보내기

이번에는 예시 코드가 아니라, 실제 코드로 적용시켜 보자. 우선 주소를 찾는 ThirdParty로 Kakao의 API를 사용할 것이다.

 

https://developers.kakao.com/docs/latest/ko/local/dev-guide#coord-to-address

 

Kakao Developers

카카오 API를 활용하여 다양한 어플리케이션을 개발해보세요. 카카오 로그인, 메시지 보내기, 친구 API, 인공지능 API 등을 제공합니다.

developers.kakao.com

좌표(위도, 경도)를 기반으로 주소로 변환하는데 필요한 문서가 잘 설명되어 있다.

 

이를 사용하여 요청을 보내보면 다음과 같이 위경도를 통해 주소를 반환받을 수 있다.

쿼리 파라미터를 통해 x, y로 logitude, latitude를 전달하고 있다.

 

postman으로 응답을 확인해 봤으니, 실제 사용할 Client를 만들어보자.

우선 다음과 같이 interface를 하나 정의해주자.

@FeignClient(name = "local-address-client", url = "${api.kakao.api-url}",
        configuration = {KakaoClientAuthHeaderConfiguration.class})
public interface KakaoAddressSearchClient {

    @GetMapping("/v2/local/geo/coord2address.json")
    KakaoAddressResponse convertAddress(@RequestParam("x") double logitude, @RequestParam("y") double latitude);
}

사실상 끝이다 ㅎㅎ, 복잡한 부분을 사실 KakaoAddressResponse라는 Dto를 통해 어떤 필드를 받아둘지 결정하는 부분이 더 어려웠다.

또한 Dto에서 역직렬화를 위해 필드와 json의 이름을 잘 확인하면서 작업해야 null값이 들어오는 일을 방지할 수 있었다.

 

이후 서비스의 로직에서는 만든 클라이언트 객체를 빈으로 주입받아 사용했다.

@Service
@RequiredArgsConstructor
public class KakaoPlaceApiService {

    private final KakaoAddressSearchClient addressSearchClient;

    public AddressConvertResponse convertAddress(double longitude, double latitude) {
        KakaoAddressResponse convertResponse = addressSearchClient.convertAddress(longitude, latitude);
        return new AddressConvertResponse(buildAddressResponseList(convertResponse));
    }
    
    // 일부 생략...
}

 

5. SpringMvc의 어노테이션을 사용할 수 있는 이유

찾아보니 FeignClient는 빈으로 생성될 때 설정된 configuration을 읽어서 생성되는데 configuration 내부에는 Client 생성 시 사용할 Decoder, Encoder, Logger, Contract 등을 빈으로 등록하는 코드가 담겨있었다.

 

이때 Client에 따로 Configuration 설정을 해주지 않으면 디폴트인 FeignClientsConfiguration를 사용해서 생성하는데 default로 적용된 Contract는 SpringMvcContract였고 덕분에 SpringMvc의 어노테이션을 사용할 수 있었다.

 

FeignClientsConfiguration

  • decoder, encoder, logger도 모두 Spring이 사용하는 객체들을 사용하도록 되어있다.

 

참고

https://forkyy.tistory.com/10

 

FeignClient 적용기

서론 현재 진행하고 있는 식당 리뷰 sns 프로젝트에서 유저 로그인 기능의 구현을 담당하고 있다. 카카오 로그인을 구현하던 중, 카카오에서 제공하는 api에 Http 요청을 보내기 위해서는 클라이언

forkyy.tistory.com

https://kafcamus.tistory.com/54

 

Spring Cloud OpenFeign 사용하기

본 글은 아래의 링크를 바탕으로 작성되었다. 우아한형제들 기술 블로그 [우아한 feign 적용기]:https://techblog.woowahan.com/2630/ Bealdung [Introduction to Spring Cloud OpenFeign]: https://www.baeldung.com/spring-cloud-openfe

kafcamus.tistory.com

 

댓글