Moises Gamio
Moises Gamio Software Engineer. Comprehensive experience in all phases of the software development lifecycle for several economic sectors.

Building a REST API Client

Building a REST API Client

This guide walks you through creating a client application that consumes a RESTful web service.

We will build a custom client code to test the rate-limiting algorithm implemented at an API Server.

Client application uses Spring’s RestTemplate, a synchronous client to perform HTTP requests.

We want to implement several calls to different endpoints. We create an interface with only one method.

1
2
3
4
5
6
7
8
9
public interface IClientAPI {

  static String apiHost = "<here_your_api_host>";
  static String tokenUri = apiHost + "/oauth/token";
  static String url = apiHost + "/v1/";
  
  public void callEndpoint() throws Exception;

}

First, we consume data from the Supplier endpoint. So, we implement the above method.

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
public final class GetSuppliers implements IClientAPI {

  private static OAuth2RestTemplate restTemplate;
  private static HttpHeaders headers;

  private static final int NRO_REQUESTS =60;

  public GetSuppliers(String clientId, String secret) {
    headers = new HttpHeaders();
    restTemplate = buildRestTemplate(clientId, secret);
  }
	
  public void callEndpoint() throws Exception {
    for (int idx = 1; idx <= NRO_REQUESTS; idx++) {
      try {
        String urlEndpoint = url + "suppliers";
        headers.set("NroClientRequest", String.valueOf(idx));
        HttpEntity<String> entity = new HttpEntity<String>(headers);
       
        ResponseEntity<List<Supplier>> responseEntity = restTemplate.exchange(urlEndpoint, HttpMethod.GET, entity, List.class);

        logger.info("X-Rate-Limit-Remaining : " + responseEntity.getHeaders().getFirst("X-Rate-Limit-Remaining"));

      } catch (Exception e) {
        logger.error("error:  " + e.getMessage());
      }
    }  
  }
  
}

Secondly, we retrieve data from the Buyer endpoint. So, we need a new custom implementation for the callEndpoint method.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public final class GetBuyers implements IClientAPI {

  private static final int NRO_REQUESTS =140;
  //code omitted for brevity

  public void callEndpoint() throws Exception {
    for (int idx = 1; idx <= NRO_REQUESTS; idx++) {
      try {
        String urlEndpoint = url + "buyers";
        headers.set("NroClientRequest", String.valueOf(idx));
        HttpEntity<String> entity = new HttpEntity<String>(headers);
       
        ResponseEntity<List<Buyer>> responseEntity = restTemplate.exchange(urlEndpoint, HttpMethod.GET, entity, List.class);

        logger.info("X-Rate-Limit-Remaining : " + responseEntity.getHeaders().getFirst("X-Rate-Limit-Remaining"));

      } catch (Exception e) {
        logger.error("error:  " + e.getMessage());
      }
    }  
  }
  
}

We will simulate a more realistic scenario where client requests arrive concurrently to the API Server.

ForkJoinPool class is an ExecutorService that helps speed up parallel processing by attempting to use all available processor cores.

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
public class RESTFulParallelClientsTest {

  public static void main(String[] args) {

    IClientAPI iClientAPI_suppliers = new GetSuppliers("<here_clientId>","<here_secret>");
    IClientAPI iClientAPI_buyers = new GetBuyers("<here_other_clientId>","<here_other_secret>");

    Callable<Void> runnableTask1 = runnableTask(iClientAPI_suppliers);
    Callable<Void> runnableTask2 = runnableTask(iClientAPI_buyers);
		
    ForkJoinPool.commonPool().invokeAll(asList(
      runnableTask1
     ,runnableTask2
     ));
  }

  private static Callable<Void> runnableTask(IClientAPI iClientAPI) {

    return () -> {
      iClientAPI.callEndpoint();
      return null;
    };
  }

}

Suppose the API Server set up a limit of 90 requests per minute for the buyer’s endpoint. Then, request number 91 is refused, and the client receives an HTTP Error code of 429.

1
2
16:10:42.454 [main] INFO RESTFulParallelClientsTest - https://api_host/v1/buyers Client request nro: 91
16:10:42.542 [main] INFO RESTFulParallelClientsTest - 429 {"title":"Too many request","status":429,"detail":"X-Rate-Limit-Retry-After-Seconds: 37","path":"/v1/buyers client: codersite.dev", "timeStamp":1696428642515}

With this test, you can simultaneously send thousands of requests to all your API endpoints. You can monitor your thread pool at the application server and see how the rate limit algorithm refuses all requests that exceed the rate limit quote.

Please donate if you find this content valuable.


java interview