Feign Documentation

repository·master·Indexed 27 days ago

https://github.com/openfeign/feign

A Java library that simplifies writing HTTP clients by binding Java interfaces to HTTP APIs using annotations. It features the annotation-error-decoder for mapping HTTP status codes to custom exceptions via @ErrorHandling, and the feign-apt-test-generator for automatically generating mock clients using the Java Annotation Processing Tool (APT).

Tokens
37K
Snippets
128
Records
165
Agent score
94%

What's inside Feign

  1. Overview of Feign

    master
    Feign is a Java-to-HTTP client binder inspired by Retrofit, JAXRS-2.0, and WebSocket. It is designed to reduce the complexity of binding code to HTTP APIs by processing annotations into templatized requests. Feign is highly customizable through decoders and error handling, making it suitable for any text-based HTTP API.
  2. Overview of Feign GraphQL APT

    master

    Feign GraphQL APT is an annotation processor for feign-graphql that generates Java records from GraphQL schemas at compile time.

    When you provide a @GraphqlSchema-annotated interface, the processor performs the following:

    • Parses the referenced .graphql schema file.
    • Validates all @GraphqlQuery strings against the schema.
    • Generates Java records for result types, input types, and enums.
    • Maps custom scalars to Java types using @Scalar annotations.
  3. Use Feign Jakarta for Jakarta-spec annotation processing

    master

    The feign-jakarta module allows Feign to use standard annotations from the Jakarta specification (currently targeting the 3.1 spec) instead of Feign's own internal annotations. This is useful for developers wanting to align their client interfaces with Jakarta EE standards.

    Important Limitations:

    • Best Effort Compatibility: This implementation is not 100% compatible with full Jakarta server interface behavior. It is a best-effort implementation.
    • Interface Only: Feign only supports processing Java interfaces. It does not support abstract or concrete classes.
    • Client vs. Server Design: While you may attempt to reuse the same interface for both client and server, Jakarta resource annotations were not originally designed for client-side processing.
  4. Use Feign JAXRS 2 for JAX-RS specification compliance

    master

    The Feign JAXRS 2 module allows you to use standard JAX-RS annotations (targeting the 1.1 spec) for defining HTTP client interfaces instead of Feign's native annotations. This is useful when you want to align your client interfaces with JAX-RS server specifications.

    Important Limitations:

    • Best Effort Compatibility: This implementation is not 100% compatible with full JAX-RS server behavior. JAX-RS annotations were designed for servers, not clients.
    • Interface Only: Feign only supports processing Java interfaces. It does not support abstract or concrete classes.
    • Package Hierarchy: Note that JAX-RS 2.0 has a different package hierarchy for client invocation compared to the 1.1 spec targeted here.
    • Null/Empty Values: An IllegalArgumentException (ISE) is raised if any annotation's value is empty or null (e.g., @Path("")).
  5. Use Feign JAX-RS for HTTP client interfaces

    master

    The Feign JAX-RS module allows you to define HTTP client interfaces using standard JAX-RS (version 1.1) annotations instead of Feign-specific ones. This is useful for aligning client definitions with JAX-RS specifications.

    Important Constraints:

    • Interface Only: Feign only supports processing Java interfaces. It does not support abstract or concrete classes.
    • Best Effort Compatibility: This implementation is a "best effort" and does not guarantee 100% compatibility with JAX-RS server-side behavior.
    • Version Note: This module targets the JAX-RS 1.1 specification. JAX-RS 2.0 uses a different package hierarchy for client invocation and may not be fully compatible.
  6. Customize ObjectMapper in Jackson-Jaxb Codec

    master

    You can provide a custom ObjectMapper to JacksonJaxbJsonEncoder and JacksonJaxbJsonDecoder to control serialization and deserialization behavior (e.g., handling null values or unknown properties).

    ObjectMapper mapper = new ObjectMapper()
            .setSerializationInclusion(JsonInclude.Include.NON_NULL)
            .configure(SerializationFeature.INDENT_OUTPUT, true)
            .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    
    GitHub github = Feign.builder()
                         .encoder(new JacksonJaxbJsonEncoder(mapper))
                         .decoder(new JacksonJaxbJsonDecoder(mapper))
                         .target(GitHub.class, "https://api.github.com");
  7. Handle Array Unwrapping and Optional Return Types

    master

    Single Result from Array Queries

    If a GraphQL query returns an array (e.g., [User!]) but the Java method returns a single object, the decoder automatically unwraps the first element. If the array is empty, null is returned.

    Optional Return Types

    You can return Optional<T> to handle nullable results. The client will return Optional.empty() if the data is missing.

    // Unwrapping array to single object
    @GraphqlQuery("query topUser($limit: Int!) { topUsers(limit: $limit) { id name email } }")
    User topUser(int limit);
    
    // Using Optional for null safety
    @GraphqlQuery("query getUser($id: String!) { getUser(id: $id) { id name email } }")
    Optional<User> findUser(String id);
  8. Configure GsonEncoder and GsonDecoder separately

    master

    If you need granular control, you can configure the encoder and decoder independently in your Feign.Builder using GsonEncoder and GsonDecoder.

    GitHub github = Feign.builder()
                         .encoder(new GsonEncoder())
                         .decoder(new GsonDecoder())
                         .target(GitHub.class, "https://api.github.com");
  9. Add Feign APT test generator to Maven classpath

    master

    The simplest way to use the generator is to add it to your project's test dependency list. The Java compiler should automatically detect and run the code generation during the build process.

    <dependency>
        <groupId>io.github.openfeign.experimental</groupId>
        <artifactId>feign-apt-test-generator</artifactId>
        <version>${feign.version}</version>
        <scope>test</scope>
    </dependency>
  10. Use Base APIs with inheritance

    master

    Feign supports single-inheritance interfaces to allow sharing common API patterns. You can define a BaseApi with common methods and type parameters, then extend it in specific service interfaces.

    @Headers("Accept: application/json")
    interface BaseApi<V> {
      @RequestLine("GET /api/{key}")
      V get(@Param("key") String key);
    
      @RequestLine("GET /api")
      List<V> list();
    
      @Headers("Content-Type: application/json")
      @RequestLine("PUT /api/{key}")
      void put(@Param("key") String key, V value);
    }
    
    interface FooApi extends BaseApi<Foo> { }
    interface BarApi extends BaseApi<Bar> { }
  11. Extending Feign via forks or separate repositories

    master

    Feign is optimized for low maintenance and prefers small, well-tested features. If a feature is large or has a high maintenance burden, it may be deferred or rejected from the main repository. In these cases, you should:

    • Fork the repository: Use a fork to experiment with and vet features before they are proposed for the main repo.
    • Create a separate repository: For large integrations (e.g., those exceeding 1000 lines of code), move the implementation to a standalone repository to ensure the sustainability of the core Feign project. An example of a successful large integration is spring-cloud-netflix.
  12. Configure Feign with Jakarta Bean Validation

    master

    To use Jakarta Bean Validation with a Feign client, register a BeanValidationMethodInterceptor using the Feign builder. You can use the default validator factory or provide an explicit Validator instance and specific validation groups.

    // Using the default validator factory
    Api api = Feign.builder()
        .methodInterceptor(BeanValidationMethodInterceptor.usingDefaultFactory())
        .target(Api.class, "https://example.com");
    
    // Using an explicit Validator and validation groups
    Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
    Feign.builder()
        .methodInterceptor(new BeanValidationMethodInterceptor(validator, Create.class))
        .target(Api.class, "https://example.com");