본문 바로가기
spring

[SpringBoot] 선언형 HTTP 클라이언트 OpenFeign이란?

by moonsiri 2025. 7. 2.
728x90
반응형

마이크로서비스 아키텍처에서 서비스 간 통신은 필수입니다.
하지만 RestTemplate 또는 WebClient로 매번 HTTP 요청을 구성하고 응답을 처리하는 것은 번거롭고 중복이 많습니다.

 

1. OpenFeign 개요

OpenFeign은 인터페이스 기반으로 외부 HTTP API를 간단하고 타입 안전하게 호출할 수 있게 도와주는 선언형(Declarative) HTTP 클라이언트입니다.

연도 주요 이벤트
2013 Netflix가 내부 프로젝트로 Feign 개발 시작
2015 Netflix OSS의 일부로 Feign 오픈 소스 공개
2016 Spring Cloud Netflix 프로젝트에서 @FeignClient 으로 통합
2019 OpenFeign이라는 이름으로 독립 프로젝트로 분리됨
Netfliex는 Feigb의 개발에서 손을 떼고 커뮤니티로 이전
2020 이후 Spring Cloud OpenFeign이 주요한 구현체로 유지되며, Spring Boot와 통합 지원 지속

 

주요 특징

  • @FeignClient 인터페이스만으로 외부 API 호출 가능
  • JSON, Form 등 다양한 HTTP 요청 포맷 지원
  • 공통 헤더, 인증 토큰 등을 위한 RequestInterceptor 지원
  • Retry, Fallback, ErrorDecoder 등 고급 기능 내장
  • Spring Cloud와 완벽 통합 (spring-cloud-starter-openfeign)

 

 

2. 기본 구성

2.1. 의존성 추가

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-hc5</artifactId>
        </dependency>
    </dependencies>

 

2.2. @EnableFeignClients 설정

@Configuration
@EnableFeignClients(defaultConfiguration = FeignConfig.class)
public class FeignConfig {  }

 

2.3. Feign 인터페이스 정의

@FeignClient(name = "userApi", url = "https://api.example.com")
public interface UserApiClient {

    @GetMapping("/users/{id}")
    UserResponse getUser(@PathVariable("id") Long id);

    @PostMapping(value = "/users", consumes = "application/json")
    UserResponse createUser(@RequestBody CreateUserRequest request);
}

@FeignClient는 실제 구현체 없이도 자동으로 프록시가 생성됩니다.

 

3. 실전 사용 예 : 토큰 인증 붙은 API 호출

3.1. 인터셉터로 헤더 자동 삽입

@Component
public class AuthHeaderInterceptor implements RequestInterceptor {

    @Autowired
    private TokenProvider tokenProvider;

    @Override
    public void apply(RequestTemplate template) {
        // template.removeHeader("Authorization");
        template.header("Authorization", "Bearer " + tokenProvider.getToken());
    }
}

 

3.2. 토큰 만료 대응 : ErrorDecoder 사용

@Component
public class CustomFeignErrorDecoder implements ErrorDecoder {

    private final ErrorDecoder defaultDecoder = new Default();

    @Override
    public Exception decode(String methodKey, Response response) {
        String body = getBody(response);

        if (body.contains("EXPIRE_TOKEN")) {
            return new RetryableException(
                response.status(),
                "Token invalid or expired. Retrying with refreshed token...",
                response.request().httpMethod(),   // ← method
                (Long) null,                       // ← retryAfter millis (null 이면 기본 정책 사용)
                response.request()                 // ← 원래 요청 정보
            );
        }

        return defaultDecoder.decode(methodKey, response);
    }

    private String getBody(Response response) {
        try (InputStream is = response.body().asInputStream()) {
            return IOUtils.toString(is, StandardCharsets.UTF_8);
        } catch (IOException e) {
            return "";
        }
    }
}

 

4. 고급 기능 요약

기능 설명
RequestInterceptor 요청 전 헤더/쿼리 등 전처리
ErrorDecoder 응답 오류 커스터마이징
Retryer 재시도 정책 설정
FallbackFactory 실패 시 fallback 지정
Decoder 응답 JSON → DTO 매핑 (기본은 Jackson 사용)

 

5. 테스트 팁

 

  • FeignClient는 일반 인터페이스이므로, 단위 테스트에서는 @MockBean 또는 Stub으로 쉽게 대체 가능
  • 통합 테스트에서는 WireMock 또는 MockWebServer 사용 추천

 

 

6. 언제 Feign을 써야 하나?

Feign은 API 호출이 많고, 인증/헤더/재시도 로직이 공통화된 프로젝트에 강력한 생산성과 유지보수성을 제공합니다.

하지만, 단순한 단건 호출이나, 복잡한 커넥션 풀 관리가 필요한 경우엔 WebClient도 고려해볼 수 있습니다.

 

 

[Reference]

https://docs.spring.io/spring-cloud-openfeign/docs/current/reference/html/

https://github.com/OpenFeign/feign

 

728x90
반응형

댓글