How to configure fiegn clients to perform HTTP requests in Spring

In our previous tutorial, we discussed how to configure and enable OpenFeign and Feign clients in a Spring boot application.

In this tutorial, we will dig deeper into Feign clients and discuss how to create and configure Feign clients to call external services using the HTTP GET, PUT. POST and DELETE functions. We will also discuss how to pass query parameters, path variables, HTTP request headers and request bodies in our requests.

Please keep in mind that this tutorial applies only to Feign clients which are created using the @FeignClient spring annotation.

If you are reading this article, then there is big chance that you are working either alone or with other teams on developing microservices and REST APIs. In this case, you might also be interested in checking out the REST API Design Rulebook (click to check the user reviews and price on Amazon). The book will help you learn which best practices to follow and common pitfalls to avoid before investing large amounts of time into implementing APIs which could prove troublesome down the road.

Mapping HTTP GET, PUT, POST and DELETE requests with a Feign client

While the an HTTP GET request can be mapped using the @GetMapping annotation as we did in our previous tutorial, an HTTP POST can be performed via a Feign client by using the @PostMapping annotation.

Similarly, POST and DELETE requests can be mapped using @PostMapping and @DeleteMapping annotations respectively.

package com.example.demo.clients;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;

@FeignClient(name = "localServiceClient", url = "localhost:1234", path = "/api/server")
public interface LocalServiceClient {

@GetMapping("/getService")
String getServerFirstServiceData(@RequestParam(name = "allCaps") boolean isAllCaps);

@DeleteMapping("/deleteService")
void deleteSomethingFromService();

@PutMapping("/putService")
String putToServerOnSecondService();

@PostMapping("/postService")
String postToServerOnSecondService();

}

Calling any of those methods will trigger the corresponding HTTP function to be called with the configured verb (PUT/POST/GET..) towards the target API. Notice that the delete method has a void return type as we are not expecting a response body to be returned.

In the next sections, we will discuss how to configure and customize those Feign client functions to suite our needs.

Configuring query parameters in Feign clients

Query parameters (AKA request parameters) are properties that are passed at the end of the URL of the service that is being called. They are usually used to narrow down the results provided by the service or to indicate a specific option that will affect the provided result. If you are not familiar with request parameters, then I suggest that you check out our article regarding configuring query parameters in REST controllers in Spring boot.

In the following example, we will configure a Feign client that will call a REST service located on host “localhost:1234” and path “/api/server/getService”. The service takes a query parameter flag called “isAllCaps”. Depending on the value flag, a String is returned either in large caps or small caps. The full path of the service will look like this:

localhost:1234/api/service/getService?isAllCaps=true

or

localhost:1234/api/service/getService?isAllCaps=false

Query parameters can be configured in Feign clients by using the @RequestParam annotation from the Spring web framework on method arguments which should be passed as query parameters when calling the remote service.

package com.example.demo.clients;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

@FeignClient(name = "localServiceClient", url = "localhost:1234", path = "/api/server")
public interface LocalServiceClient {

    @GetMapping("/getService")
    String getServerFirstServiceData(@RequestParam boolean isAllCaps);
    
}

This will automatically add a query parameter with the name “isAllCaps” into the request URL when calling the remote service.

If you would like to give the query parameter a different name than the method argument name, then you can configure the @RequestParam annotation with the name property.


    @GetMapping("/firstService")
    String getServerFirstServiceData(@RequestParam(name = "allCaps") boolean isAllCaps);

Now you can call the client just like any other spring service with the boolean argument value that is needed.

public String delegateFirstServiceAllCaps(){
return localServiceClient.getServerFirstServiceData(true);
}

If you have multiple query parameter values to be passed, then you can simply use multiple method arguments to pass those values.

Passing arguments through the request body of HTTP requests

When performing HTTP POST or HTTP put, you will often find that you will need to pass some information inside the request body, such as JSON data or simple parameters that are needed to process your request.

This is easily configured by adding a method argument which has the annotation @RequestBody.

@PutMapping("/putService")
String putToServerOnThirdService(@RequestParam int interations, @RequestBody String value);

This will instruct Feign to issue a PUT call to the service, adding the query paramter “iterations” to the request URL and the string value in the HTTP request body.

You can also omit the @RequestBody annotation if you intend to pass the HTTP request body payload via the first method argument. In this case, our method would look like this:

@PostMapping("/postService")
String postToServerOnSecondService(String value, @RequestParam int id);

You can pass on more complicated data types as the response body. By default, those entities would then automatically be automatically serialized into JSON and sent to the target server. For example, let us create a DTO called “MyClass” and send it through the client.

public class MyClass{

    int abc;

    String something;

    String somethingElse;

    public MyClass(int abc, String something, String somethingElse) {
        this.abc = abc;
        this.something = something;
        this.somethingElse = somethingElse;
    }

Let us adapt our client to accept the MyClass entity.

@PostMapping("/postService")
String postToServerOnSecondService(Whatever value);

Next, let us call the feign client and see how the request body will look like on the target service.

localServiceClient.postToServerOnSecondService(new MyClass(123, "something here", "some other string"));

And here is the request on the other side:

{"abc":123,"something":"something here","somethingElse":"some other string"}

Configuring feign clients with path variables

Path variables are parts of the actual address being accessed. They are part of the path (URL) and change in value depending on the resource we try to access (hence the name path “variables”). You can read more in depth about path variables and how to configure them in your own Spring controllers in this article.

To configure path vairables in feign clients, we need to

  • indicate which part of the URL will be replaced by the path variable and
  • indicate the value that will be used within the path.

Let us assume that we have a service which accepts an ID as the last path of the URL. For example:

…./thirdService/{id}

Let us map this into a feign client method. To map the path variable to a method argument in a feign client, we use the @PathVariable annotation from Spring.

@GetMapping("/thirdService/{id}")
String getThirdService(@PathVariable(name = "id") int id);

Using the annotation as such, OpenFeign will substitute the {id} part of the path with the value of the integer id. You can omit the “name = …” configuration if your variable name is the same as the placeholder name in the URL.

How to add HTTP headers to Open feign client calls

Sometimes you need to add additional information to your function calls in the form of HTTP headers. For example, when passing on cookies or tokens.

To add HTTP headers to OpenFeign clients with Spring, you can use the @RequestHeader annotation next to the method argument which will represent the header value. For example, if we wanted to add an HTTP header named “ABC-TOKEN” to our previous example, then we can do it as follows:

@GetMapping("/thirdService/{id}")
String getThirdService(@RequestHeader(name = "ABC-TOKEN") String abcToken,
@PathVariable(name = "id") int id);

The service method can then be called just as we did in all our previous examples.

Summary and final thoughts

In this tutorial, we discussed how to configure feign clients to perform HTTP calls in the form of PUT, POST, GET and DELETE using the @PutMapping, @PostMapping, @GetMapping and @DeleteMapping respectively.

Please note that you can annotate your feign client with the @RequestMapping annotation as well if you are using an older version of Spring. In this case, please do not forget to set the intended HTTP method. For example:

@RequestMapping(value = "/postService", method = RequestMethod.GET)
String someService();

We also discussed how to map path variables, query parameters and the request body using the annotations @PathVariable, @QueryParam and @RequestBody respectively.

Finally, we discussed how to pass HTTP request headers via feign clients using the @RequestHeader annotation.