Skip to content

Spring Cloud OpenFeign Interceptor#

Request Interceptor Concept#

  • HTTP Interceptors allow us to check or modify all the incoming or outgoing HTTP requests in our application. We can use them if we want to apply something like an authorization header to all the requests.
  • There are many use-cases where HTTP Interceptors can come in handy. Since they intercept all the API calls, we can use them to apply some logic before or after the API call. These interceptors have access to the complete request and response body. So, if we want to apply some logic to all the requests, we can add it once using an interceptor instead of writing separate code for every request. Here are some examples of things we can do.
    • Apply an authorization header to all the requests.
    • Prefix all the requests with the server name.
    • Log all the requests and responses.
    • Set a global error catch.
    • Resend the request if it fails.

Basic Auth Request Interceptor#

  • In spring-cloud-starter-openfeign dependency , we have been already provided the BasicAuthRequestInterceptor for supporting calling to apis which require the basic authentication token.
  • So, let's start with the example below then we can understand it easily.

Prepare#

  • So to begin with the example, we need to prepare some application services as below:

 #zoom

  • In this image we will use Postman to call to the Client Application that we will configure below, then from this Client Application, it will call to the Resource Application which is configured with Basic Authentication.
  • For the source code of Resource Application you can download here.
  • Now, let's create and configure the Client Application as below.

Dependencies#

  • To use BasicAuthRequestInterceptor in OpenFeign, you need to import the dependency below into the pom.xml of your Client Application which is a Spring Boot application.
pom.xml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
....

<!--Spring cloud openfeign-->  
<dependency>  
    <groupId>org.springframework.cloud</groupId>  
    <artifactId>spring-cloud-starter-openfeign</artifactId>  
    <version>3.1.0</version>  
</dependency>

....

Create Feign Configuration#

  • Let's create a configuration class with name BasicAuthFeignConfig for configuring BasicAuthRequestInterceptor as below:
BasicAuthFeignConfig.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
package com.springboot.cloud.openfeign.interceptor.service.config;  

import feign.auth.BasicAuthRequestInterceptor;  
import org.springframework.beans.factory.annotation.Value;  
import org.springframework.context.annotation.Bean;  

//We should not put the annotation @Configuration right here because it will apply the BasicAuthRequestInterceptor for all FeignClients  
public class BasicAuthFeignConfig {  

    @Value("${spring.security.basic.username}")  
    private String username;  

    @Value("${spring.security.basic.password}")  
    private String password;  

    @Bean  
    public BasicAuthRequestInterceptor basicAuthRequestInterceptor() {  
        return new BasicAuthRequestInterceptor(username, password);  
    }  

}
  • As you can see, we will create a bean BasicAuthRequestInterceptor with the username and password that we load from the application.yml.
application.yml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
spring:
  security:
    basic:
      url: http://localhost:8083
      username: "user"
      password: "12345"

logging:
  level:
    com.springboot.cloud.openfeign.interceptor.service.api: DEBUG

feign:
  client:
    config:
      default:
        loggerLevel: full
  • If you don't want to apply the BasicAuthRequestInterceptor for all FeignClients, so please don't put the annotation @Configuration in class BasicAuthFeignConfig.java.

FeignClient Configuration#

  • Now we will create an adapter interface name SpringBasicAuthClient to configure FeignClient with target api as below:
SpringBasicAuthClient.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
package com.springboot.cloud.openfeign.interceptor.service.api;  

import com.springboot.cloud.openfeign.interceptor.service.config.BasicAuthFeignConfig;  
import org.springframework.cloud.openfeign.FeignClient;  
import org.springframework.http.MediaType;  
import org.springframework.web.bind.annotation.RequestMapping;  
import org.springframework.web.bind.annotation.RequestMethod;  

@FeignClient(name = "springBasicAuthClient", url = "${spring.security.basic.url}", configuration = {BasicAuthFeignConfig.class})  
public interface SpringBasicAuthClient {  

    @RequestMapping(method = RequestMethod.GET, path = "/welcome", consumes = MediaType.TEXT_HTML_VALUE)  
    String sayWelcome();  

}
  • As we can see, in the @FeignClient annotation, we will provide a client name, the server domain URL that we need to call to and we will load the BasicAuthRequestInterceptor configuration class that we want to apply for this FeignClient by using param configuration = {BasicAuthFeignConfig.class}.

Controller#

  • Now, we need to create a simple controller as below for testing with Postman.
OpenFeignInterceptorController.class
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
package com.springboot.cloud.openfeign.interceptor.service.controller;

import com.springboot.cloud.openfeign.interceptor.service.api.SpringBasicAuthClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class OpenFeignInterceptorController {

    @Autowired
    private SpringBasicAuthClient springBasicAuthClient;

    @RequestMapping(method = RequestMethod.GET, path = "/v1/basic/auth/interceptor/welcome")
    public ResponseEntity<String> getWelcomeMessageWithBasicAuthInterceptor() {
        return ResponseEntity.ok(this.springBasicAuthClient.sayWelcome());
    }

}

Testing#

  • Finally, let's start our Client Application and Resource Application, then you postman to call the exported api above. Then you should see the 200 result as below.

 #zoom

  • Then if you check the log in the console, you can see Authorization header had been added into the request to the Resource Application for getting the data.

 #zoom

Header Interceptor#

  • In some cases, we might need to add some custom request headers into our requests for calling apis. In this case we would like to use RequestInterceptor of OpenFeign which will give us more options for configuring Request Interceptor.

Prepare#

  • Like the example above, we also follow the diagram and services that we created. But when we test with the postman, we will look into the console log to check our custom headers have been added into the requests to Resource Server

 #zoom

Create Feign Configuration#

  • Let's create a configuration class with name FeignHeaderConfig for configuring RequestInterceptor as below:
FeignHeaderConfig.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.springboot.cloud.openfeign.interceptor.service.config;  

import feign.RequestInterceptor;  
import org.springframework.beans.factory.annotation.Value;  
import org.springframework.context.annotation.Bean;  

import java.util.UUID;  

//We should not put the annotation @Configuration right here because it will apply the BasicAuthRequestInterceptor for all FeignClients  
public class FeignHeaderConfig {  

    @Value("${spring.security.basic.token}")  
    private String token;  

    @Bean  
    public RequestInterceptor requestInterceptor() {  
        return requestTemplate -> {  
            requestTemplate.header("Content-Type", "application/json");  
            requestTemplate.header("Accept", "application/json");  
            requestTemplate.header("random-uuid", UUID.randomUUID().toString());  
            requestTemplate.header("Authorization", token);  
        };  
    }  

}
  • As you can see, we will create a bean RequestInterceptor with some example headers and an authorization token that we load from the application.yml.
application.yml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
spring:  
  security:  
    basic:  
      url: http://localhost:8083  
      username: "user"  
      password: "12345"  
      token: "Basic dXNlcjoxMjM0NQ=="

logging:  
  level:  
    com.springboot.cloud.openfeign.interceptor.service.api: DEBUG  

feign:  
  client:  
    config:  
      default:  
        loggerLevel: full

FeignClient Configuration#

  • Now we will create an adapter interface name SpringCustomHeaderClient to configure FeignClient with target api as below:
SpringCustomHeaderClient.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
package com.springboot.cloud.openfeign.interceptor.service.api;  

import com.springboot.cloud.openfeign.interceptor.service.config.FeignHeaderConfig;  
import org.springframework.cloud.openfeign.FeignClient;  
import org.springframework.http.MediaType;  
import org.springframework.web.bind.annotation.RequestMapping;  
import org.springframework.web.bind.annotation.RequestMethod;  

@FeignClient(name = "springCustomHeaderClient", url = "${spring.security.basic.url}", configuration = {FeignHeaderConfig.class})  
public interface SpringCustomHeaderClient {  

    @RequestMapping(method = RequestMethod.GET, path = "/welcome", consumes = MediaType.TEXT_HTML_VALUE)  
    String sayWelcome();  

}
  • Like the FeignClient configuration that we did before in SpringBasicAuthClient, now we just need to change the name and use param configuration = {FeignHeaderConfig.class} to load the FeignHeaderConfig which will be applied for this FeignClient.

Controller#

  • Now, we need to add a new api into the controller that we created before.
OpenFeignInterceptorController.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package com.springboot.cloud.openfeign.interceptor.service.controller;  

import com.springboot.cloud.openfeign.interceptor.service.api.SpringBasicAuthClient;  
import com.springboot.cloud.openfeign.interceptor.service.api.SpringCustomHeaderClient;  
import org.springframework.beans.factory.annotation.Autowired;  
import org.springframework.http.ResponseEntity;  
import org.springframework.web.bind.annotation.RequestMapping;  
import org.springframework.web.bind.annotation.RequestMethod;  
import org.springframework.web.bind.annotation.RestController;  

@RestController  
public class OpenFeignInterceptorController {  

    @Autowired  
    private SpringBasicAuthClient springBasicAuthClient;  

    @Autowired  
    private SpringCustomHeaderClient springCustomHeaderClient;  

    @RequestMapping(method = RequestMethod.GET, path = "/v1/basic/auth/interceptor/welcome")  
    public ResponseEntity<String> getWelcomeMessageWithBasicAuthInterceptor() {  
        return ResponseEntity.ok(this.springBasicAuthClient.sayWelcome());  
    }  

    @RequestMapping(method = RequestMethod.GET, path = "/v1/custom/header/interceptor/welcome")  
    public ResponseEntity<String> getWelcomeMessageWithCustomerHeaders() {  
        return ResponseEntity.ok(this.springCustomHeaderClient.sayWelcome());  
    }

}

Testing#

  • Finally, let's start our Client Application and Resource Application, then you postman to call the exported api above. Then you should see the 200 result as below.

 #zoom

  • Then if you check the log in the console, you can see all your custom headers had been added into the request to the Resource Application for getting the data.

 #zoom

OpenFeign Interceptor With OAuth2 Client#

See Also#

References#