IT 개발 라이프/Back_End

Feign Client란? 🤔

10Biliion 2024. 12. 3. 10:30

Feign Client는 Spring Cloud에서 제공하는 HTTP 클라이언트 라이브러리로, RESTful API 호출을 더욱 간결하고 선언적으로 처리할 수 있게 도와줍니다. Java 코드로 API 호출을 마치 인터페이스 메서드를 호출하듯 작성할 수 있어 생산성과 가독성이 높아집니다. ✨


Feign Client의 주요 특징 🌟

  1. 인터페이스 기반: API를 호출할 때 복잡한 코드를 작성할 필요 없이 인터페이스와 어노테이션만으로 구현할 수 있습니다.
  2. 내장형 로드 밸런싱: Spring Cloud LoadBalancer와 연동하여 클라이언트 부하 분산을 자동으로 처리합니다.
  3. 확장 가능: 커스터마이징을 통해 로깅, 요청/응답 변환기 등을 손쉽게 추가할 수 있습니다.
  4. 타사 라이브러리 통합: OkHttp, Apache HttpClient 등 다양한 HTTP 클라이언트를 지원합니다.

예제: Feign Client로 REST API 호출하기 🛠️

1. 의존성 추가하기 📦

먼저, build.gradle 또는 pom.xml에 Feign 의존성을 추가합니다:

Gradle:

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

Maven:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

2. Feign Client 인터페이스 정의하기 ✍️

예를 들어, JSONPlaceholder API를 호출한다고 가정해보겠습니다:

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@FeignClient(name = "jsonPlaceholderClient", url = "https://jsonplaceholder.typicode.com")
public interface JsonPlaceholderClient {

    @GetMapping("/posts/{id}")
    Post getPostById(@PathVariable("id") Long id);

    @GetMapping("/posts")
    List getAllPosts();
}

여기서:

  • @FeignClient: Feign Client 인터페이스임을 선언합니다.
  • name: 이 클라이언트를 구분짓는 이름입니다.
  • url: 호출할 API의 기본 URL입니다.
  • @GetMapping: HTTP GET 메서드를 호출할 경로를 지정합니다.

Post 클래스는 API의 응답 구조에 맞게 정의되어야 합니다:

@Data
public class Post {
    private Long id;
    private Long userId;
    private String title;
    private String body;
}

3. Feign Client 사용하기 🚀

이제 작성한 Feign Client를 서비스나 컨트롤러에서 사용할 수 있습니다:

import org.springframework.stereotype.Service;

@Service
public class PostService {

    private final JsonPlaceholderClient jsonPlaceholderClient;

    public PostService(JsonPlaceholderClient jsonPlaceholderClient) {
        this.jsonPlaceholderClient = jsonPlaceholderClient;
    }

    public Post getPostById(Long id) {
        return jsonPlaceholderClient.getPostById(id);
    }

    public List<Post> getAllPosts() {
        return jsonPlaceholderClient.getAllPosts();
    }
}

컨트롤러에서 호출해봅시다:

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class PostController {

    private final PostService postService;

    public PostController(PostService postService) {
        this.postService = postService;
    }

    @GetMapping("/posts/{id}")
    public Post getPostById(@PathVariable Long id) {
        return postService.getPostById(id);
    }

    @GetMapping("/posts")
    public List<Post> getAllPosts() {
        return postService.getAllPosts();
    }
}

Feign Client 커스터마이징 🛠️

로깅 추가하기 📝

Feign Client의 요청/응답 로그를 확인하려면 다음 설정을 추가하세요:

  1. application.yml 설정:
logging:
  level:
    com.example.JsonPlaceholderClient: DEBUG
  1. Feign Logger Bean 등록:
import feign.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class FeignConfig {

    @Bean
    public Logger.Level feignLoggerLevel() {
        return Logger.Level.FULL;
    }
}

오류 처리 핸들러 추가하기 ⚠️

Feign Client는 기본적으로 오류 응답을 그대로 던지므로, 이를 사용자 정의 예외로 처리하려면 **ErrorDecoder**를 구현합니다:

import feign.Response;
import feign.codec.ErrorDecoder;

public class CustomErrorDecoder implements ErrorDecoder {

    @Override
    public Exception decode(String methodKey, Response response) {
        switch (response.status()) {
            case 400:
                return new BadRequestException("잘못된 요청입니다.");
            case 404:
                return new NotFoundException("리소스를 찾을 수 없습니다.");
            default:
                return new Exception("알 수 없는 오류가 발생했습니다.");
        }
    }
}

그리고 Feign Client에 이 오류 디코더를 적용합니다:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class FeignConfig {

    @Bean
    public ErrorDecoder errorDecoder() {
        return new CustomErrorDecoder();
    }
}

마무리 🎉

Feign Client를 활용하면 복잡한 HTTP 클라이언트 코드를 줄이고, 선언적인 방식으로 API 호출을 간편하게 작성할 수 있습니다. 필요한 경우 로깅, 오류 처리, 커스터마이징 등을 통해 요구사항에 맞게 확장할 수도 있습니다. 🚀