Skip to content


Subversion checkout URL

You can clone with
Download ZIP
Feign makes writing java http clients easier
Java Shell
Latest commit b2e9b6f @adriancole adriancole Merge pull request #295 from dstepanov/jaxrs-npe-method-annotation-order
JAX-RS: Fix NPE when @Path is first on a method and without leading slash
Failed to load latest commit information.
benchmark Bumps dependency versions for integrations
codequality Build upgrades
core SynchronousMethodHandler does not wrap exceptions thrown by Decoder#d…
example-github Updates examples to 8.7.0
example-wikipedia Updates examples to 8.7.0
gradle/wrapper Bumps dependency versions for integrations
gson Adds Feign.Builder.decode404() to reduce boilerplate for empty semantics
httpclient Added support for spaces in path
hystrix add HystrixCommand support
jackson-jaxb Adds Feign.Builder.decode404() to reduce boilerplate for empty semantics
jackson Adds Feign.Builder.decode404() to reduce boilerplate for empty semantics
jaxb Adds Feign.Builder.decode404() to reduce boilerplate for empty semantics
jaxrs JAXRS: Fix NPE when @Path is first on a method
okhttp Supports POST without a body parameter
ribbon Bumps dependency versions for integrations
sax Adds Feign.Builder.decode404() to reduce boilerplate for empty semantics
slf4j Bumps dependency versions for integrations
.gitignore added dagger IDE setup for annotation parsing via gradle idea and ecl…
.travis.yml Moves off legacy travis containers Adds Feign.Builder.decode404() to reduce boilerplate for empty semantics Reformats code according to Google Java Style
LICENSE Restructure into smaller files
NOTICE default client: use custom HostnameVerifier if overridden Fix 404 issue for Github sample
build.gradle Bumps dependency versions for integrations Enable Maven Central sync Build upgrades
gradlew Upgrading to Gradle 1.4
gradlew.bat Upgrade to Gradle 1.1. Move to 2.2.9 for travisci release
settings.gradle add HystrixCommand support

Feign makes writing java http clients easier

Join the chat at Feign is a java to http client binder inspired by Retrofit, JAXRS-2.0, and WebSocket. Feign's first goal was reducing the complexity of binding Denominator uniformly to http apis regardless of restfulness.

Why Feign and not X?

You can use tools like Jersey and CXF to write java clients for ReST or SOAP services. You can write your own code on top of http transport libraries like Apache HC. Feign aims to connect your code to http apis with minimal overhead and code. Via customizable decoders and error handling, you should be able to write to any text-based http api.

How does Feign work?

Feign works by processing annotations into a templatized request. Just before sending it off, arguments are applied to these templates in a straightforward fashion. While this limits Feign to only supporting text-based apis, it dramatically simplified system aspects such as replaying requests. It is also stupid easy to unit test your conversions knowing this.


Usage typically looks like this, an adaptation of the canonical Retrofit sample.

interface GitHub {
  @RequestLine("GET /repos/{owner}/{repo}/contributors")
  List<Contributor> contributors(@Param("owner") String owner, @Param("repo") String repo);

static class Contributor {
  String login;
  int contributions;

public static void main(String... args) {
  GitHub github = Feign.builder()
                       .decoder(new GsonDecoder())
                       .target(GitHub.class, "");

  // Fetch and print a list of the contributors to this library.
  List<Contributor> contributors = github.contributors("netflix", "feign");
  for (Contributor contributor : contributors) {
    System.out.println(contributor.login + " (" + contributor.contributions + ")");


Feign has several aspects that can be customized. For simple cases, you can use Feign.builder() to construct an API interface with your custom components. For example:

interface Bank {
  @RequestLine("POST /account/{id}")
  Account getAccountInfo(@Param("id") String id);
Bank bank = Feign.builder().decoder(new AccountDecoder()).target(Bank.class, "");

Multiple Interfaces

Feign can produce multiple api interfaces. These are defined as Target<T> (default HardCodedTarget<T>), which allow for dynamic discovery and decoration of requests prior to execution.

For example, the following pattern might decorate each request with the current url and auth token from the identity service.

Feign feign = Feign.builder().build();
CloudDNS cloudDNS = CloudIdentityTarget<CloudDNS>(user, apiKey));


Feign includes example GitHub and Wikipedia clients. The denominator project can also be scraped for Feign in practice. Particularly, look at its example daemon.


Feign intends to work well within Netflix and other Open Source communities. Modules are welcome to integrate with your favorite projects!


Gson includes an encoder and decoder you can use with a JSON API.

Add GsonEncoder and/or GsonDecoder to your Feign.Builder like so:

GsonCodec codec = new GsonCodec();
GitHub github = Feign.builder()
                     .encoder(new GsonEncoder())
                     .decoder(new GsonDecoder())
                     .target(GitHub.class, "");


Jackson includes an encoder and decoder you can use with a JSON API.

Add JacksonEncoder and/or JacksonDecoder to your Feign.Builder like so:

GitHub github = Feign.builder()
                     .encoder(new JacksonEncoder())
                     .decoder(new JacksonDecoder())
                     .target(GitHub.class, "");


SaxDecoder allows you to decode XML in a way that is compatible with normal JVM and also Android environments.

Here's an example of how to configure Sax response parsing:

api = Feign.builder()
           .target(Api.class, "https://apihost");


JAXB includes an encoder and decoder you can use with an XML API.

Add JAXBEncoder and/or JAXBDecoder to your Feign.Builder like so:

api = Feign.builder()
           .encoder(new JAXBEncoder())
           .decoder(new JAXBDecoder())
           .target(Api.class, "https://apihost");


JAXRSContract overrides annotation processing to instead use standard ones supplied by the JAX-RS specification. This is currently targeted at the 1.1 spec.

Here's the example above re-written to use JAX-RS:

interface GitHub {
  @GET @Path("/repos/{owner}/{repo}/contributors")
  List<Contributor> contributors(@PathParam("owner") String owner, @PathParam("repo") String repo);
GitHub github = Feign.builder()
                     .contract(new JAXRSContract())
                     .target(GitHub.class, "");           


OkHttpClient directs Feign's http requests to OkHttp, which enables SPDY and better network control.

To use OkHttp with Feign, add the OkHttp module to your classpath. Then, configure Feign to use the OkHttpClient:

GitHub github = Feign.builder()
                     .client(new OkHttpClient())
                     .target(GitHub.class, "");


RibbonClient overrides URL resolution of Feign's client, adding smart routing and resiliency capabilities provided by Ribbon.

Integration requires you to pass your ribbon client name as the host part of the url, for example myAppProd.

MyService api = Feign.builder().client(RibbonClient.create()).target(MyService.class, "https://myAppProd");


HystrixFeign configures circuit breaker support provided by Hystrix.

To use Hystrix with Feign, add the Hystrix module to your classpath. Then use the HystrixFeign builder:

MyService api = HystrixFeign.builder().target(MyService.class, "https://myAppProd");


SLF4JModule allows directing Feign's logging to SLF4J, allowing you to easily use a logging backend of your choice (Logback, Log4J, etc.)

To use SLF4J with Feign, add both the SLF4J module and an SLF4J binding of your choice to your classpath. Then, configure Feign to use the Slf4jLogger:

GitHub github = Feign.builder()
                     .logger(new Slf4jLogger())
                     .target(GitHub.class, "");


Feign.builder() allows you to specify additional configuration such as how to decode a response.

If any methods in your interface return types besides Response, String, byte[] or void, you'll need to configure a non-default Decoder.

Here's how to configure JSON decoding (using the feign-gson extension):

GitHub github = Feign.builder()
                     .decoder(new GsonDecoder())
                     .target(GitHub.class, "");


The simplest way to send a request body to a server is to define a POST method that has a String or byte[] parameter without any annotations on it. You will likely need to add a Content-Type header.

interface LoginClient {
  @RequestLine("POST /")
  @Headers("Content-Type: application/json")
  void login(String content);
client.login("{\"user_name\": \"denominator\", \"password\": \"secret\"}");

By configuring an Encoder, you can send a type-safe request body. Here's an example using the feign-gson extension:

static class Credentials {
  final String user_name;
  final String password;

  Credentials(String user_name, String password) {
    this.user_name = user_name;
    this.password = password;

interface LoginClient {
  @RequestLine("POST /")
  void login(Credentials creds);
LoginClient client = Feign.builder()
                          .encoder(new GsonEncoder())
                          .target(LoginClient.class, "");

client.login(new Credentials("denominator", "secret"));

@Body templates

The @Body annotation indicates a template to expand using parameters annotated with @Param. You will likely need to add a Content-Type header.

interface LoginClient {

  @RequestLine("POST /")
  @Headers("Content-Type: application/xml")
  @Body("<login \"user_name\"=\"{user_name}\" \"password\"=\"{password}\"/>")
  void xml(@Param("user_name") String user, @Param("password") String password);

  @RequestLine("POST /")
  @Headers("Content-Type: application/json")
  // json curly braces must be escaped!
  @Body("%7B\"user_name\": \"{user_name}\", \"password\": \"{password}\"%7D")
  void json(@Param("user_name") String user, @Param("password") String password);
client.xml("denominator", "secret"); // <login "user_name"="denominator" "password"="secret"/>
client.json("denominator", "secret"); // {"user_name": "denominator", "password": "secret"}

Advanced usage

Base Apis

In many cases, apis for a service follow the same conventions. Feign supports this pattern via single-inheritance interfaces.

Consider the example:

interface BaseAPI {
  @RequestLine("GET /health")
  String health();

  @RequestLine("GET /all")
  List<Entity> all();

You can define and target a specific api, inheriting the base methods.

interface CustomAPI extends BaseAPI {
  @RequestLine("GET /custom")
  String custom();

In many cases, resource representations are also consistent. For this reason, type parameters are supported on the base api interface.

@Headers("Accept: application/json")
interface BaseApi<V> {

  @RequestLine("GET /api/{key}")
  V get(@Param("key") String);

  @RequestLine("GET /api")
  List<V> list();

  @Headers("Content-Type: application/json")
  @RequestLine("PUT /api/{key}")
  void put(@Param("key") String, V value);

interface FooApi extends BaseApi<Foo> { }

interface BarApi extends BaseApi<Bar> { }


You can log the http messages going to and from the target by setting up a Logger. Here's the easiest way to do that:

GitHub github = Feign.builder()
                     .decoder(new GsonDecoder())
                     .logger(new Logger.JavaLogger().appendToFile("logs/http.log"))
                     .target(GitHub.class, "");

The SLF4JLogger (see above) may also be of interest.

Request Interceptors

When you need to change all requests, regardless of their target, you'll want to configure a RequestInterceptor. For example, if you are acting as an intermediary, you might want to propagate the X-Forwarded-For header.

static class ForwardedForInterceptor implements RequestInterceptor {
  @Override public void apply(RequestTemplate template) {
    template.header("X-Forwarded-For", "");
Bank bank = Feign.builder()
                 .requestInterceptor(new ForwardedForInterceptor())
                 .target(Bank.class, "");

Another common example of an interceptor would be authentication, such as using the built-in BasicAuthRequestInterceptor.

Bank bank = Feign.builder()
                 .requestInterceptor(new BasicAuthRequestInterceptor(username, password))
                 .target(Bank.class, "");

Custom @Param Expansion

Parameters annotated with Param expand based on their toString. By specifying a custom Param.Expander, users can control this behavior, for example formatting dates.

@RequestLine("GET /?since={date}") Result list(@Param(value = "date", expander = DateToMillis.class) Date date);
Something went wrong with that request. Please try again.