Home/Learn/Spring Boot/Feign Client

Feign Client

Advanced
Production & Advanced

Feign is a declarative HTTP client — define an interface annotated with Spring MVC annotations and Feign generates the implementation. Add Resilience4j for circuit breaking and retry to make inter-service calls production-safe.

Overview

In a microservices architecture, services call each other over HTTP. Writing RestTemplate or WebClient code for each call is repetitive and error-prone. Spring Cloud OpenFeign generates a proxy implementation from an annotated interface. Adding @EnableFeignClients scans for @FeignClient interfaces. Combine with Resilience4j for circuit breaking (stop cascading failures) and retry (handle transient errors).

@FeignClient Setup

Add spring-cloud-starter-openfeign. Annotate the interface with @FeignClient specifying the service URL or Eureka service name. Use Spring MVC annotations on the methods — Feign generates the HTTP calls.

Java — @FeignClient interface with Spring MVC annotations
<!-- pom.xml -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
    <groupId>io.github.resilience4j</groupId>
    <artifactId>resilience4j-spring-boot3</artifactId>
</dependency>

// Enable Feign on main class or @Configuration
@SpringBootApplication
@EnableFeignClients
public class OrderServiceApp { ... }

// Feign client interface — Feign generates the implementation
@FeignClient(
    name = "payment-service",
    url = "${services.payment.url:http://payment-service}",
    fallbackFactory = PaymentClientFallbackFactory.class
)
public interface PaymentClient {

    @PostMapping("/api/v1/payments/charge")
    PaymentResponse charge(@RequestBody ChargeRequest request);

    @GetMapping("/api/v1/payments/{paymentId}")
    PaymentResponse getPayment(@PathVariable String paymentId);

    @DeleteMapping("/api/v1/payments/{paymentId}/refund")
    RefundResponse refund(@PathVariable String paymentId);
}

// Inject and use exactly like any other Spring bean
@Service
public class OrderService {
    private final PaymentClient paymentClient;

    public Order placeOrder(PlaceOrderRequest req) {
        // Feign handles HTTP, serialization, error mapping
        PaymentResponse payment = paymentClient.charge(
            new ChargeRequest(req.userId(), req.total(), req.paymentMethod())
        );
        return createOrder(req, payment.getId());
    }
}

Fallback, Error Handling and Retry

FallbackFactory creates fallback implementations that receive the exception — return cached data or a default response. Configure timeouts and retries in application.yml.

Java + YAML — FallbackFactory with circuit breaker and retry config
// Fallback factory — receives the exception causing the fallback
@Component
public class PaymentClientFallbackFactory
        implements FallbackFactory<PaymentClient> {

    @Override
    public PaymentClient create(Throwable cause) {
        return new PaymentClient() {
            @Override
            public PaymentResponse charge(ChargeRequest request) {
                log.error("Payment service unavailable: {}", cause.getMessage());
                throw new PaymentServiceUnavailableException(
                    "Payment service is temporarily unavailable");
            }

            @Override
            public PaymentResponse getPayment(String paymentId) {
                return PaymentResponse.notAvailable(paymentId);
            }
        };
    }
}

# application.yml — Feign timeouts + Resilience4j circuit breaker
spring:
  cloud:
    openfeign:
      client:
        config:
          payment-service:
            connect-timeout: 2000   # 2s connection timeout
            read-timeout: 5000      # 5s read timeout

resilience4j:
  circuitbreaker:
    instances:
      payment-service:
        failure-rate-threshold: 50        # open circuit at 50% failures
        wait-duration-in-open-state: 30s  # wait 30s before trying again
        sliding-window-size: 10           # evaluate last 10 calls
  retry:
    instances:
      payment-service:
        max-attempts: 3
        wait-duration: 500ms

Key Points to Remember

  • 1@EnableFeignClients on your main class triggers scanning for @FeignClient interfaces.
  • 2Feign interfaces use Spring MVC annotations (@GetMapping, @RequestBody etc.) — familiar and readable.
  • 3FallbackFactory (preferred over Fallback) receives the exception so you can log and handle it properly.
  • 4Always configure connect and read timeouts — Feign has no defaults, meaning it can wait forever.
  • 5Combine with Resilience4j circuit breaker to stop cascading failures when a downstream service is down.
  • 6For async inter-service calls, use WebClient instead of Feign — Feign is synchronous/blocking.

Interview Questions

Sign in to ask Aria
1

What is the difference between Feign and RestTemplate?

EasyWipro
2

What is a circuit breaker and why is it important for inter-service calls?

MediumAmazon
3

What is the difference between FallbackFactory and a plain Fallback class?

MediumThoughtWorks
4

How do you configure a read timeout for a Feign client?

EasyInfosys
5

How would you pass authentication headers from the incoming request to a Feign outgoing call?

HardAtlassian

Ask Aria about Feign Client

Your personal AI tutor — ask anything about this concept

Revision Status

Personal Notes

Sign in to save personal notes for this topic.

Discussion

Sign in to join the discussion.

Loading discussion…