Search code examples
javarestspring-bootintegration-testing

Forbidden when RestTemplate call an external API (Cloudflare server)


I'm using one REST API inside my REST service. Everything works when I call the API from Chrome or Postman, but a Forbbiden response is returned when I call from my application.

PS: I'm using a Java Spring Boot project.

Test Method:

public static void main(String[] args) {
    final String uri = "https://swapi.co/api/planets?search=Alderaan";
    System.out.println(new RestTemplate().getForObject(uri, String.class));
}

Produces:

20:58:01.436 [main] DEBUG org.springframework.web.client.RestTemplate - HTTP GET swapi.co/api/planets?search=Alderaan 
20:58:01.461 [main] DEBUG org.springframework.web.client.RestTemplate - Accept=[text/plain, application/json, application/*+json, */*]
20:58:02.577 [main] DEBUG org.springframework.web.client.RestTemplate - Response 403 FORBIDDEN
Exception in thread "main" org.springframework.web.client.HttpClientErrorException$Forbidden: 403 Forbidden

The external API: https://swapi.co/documentation


Solution

  • Everything works when I specify some "user-agent" in the Headers.

    It seams to be a restriction on CloudFlare: https://support.cloudflare.com/hc/en-us/articles/200170086-What-does-the-Browser-Integrity-Check-do-

    The user-agent of my application is my Java version (Java/1.8.0_151). If you try this user-agent you will receive a restrict access message from CloudFlare.

    curl:

    curl -H "User-Agent: Java/1.8.0_151" https://swapi.co/api/planets/?search=Alderaan
    

    response: Access denied | swapi.co used Cloudflare to restrict access

    This code solve the problem:

     HttpHeaders headers = new HttpHeaders();
     headers.add("user-agent", "Application");
     HttpEntity<String> entity = new HttpEntity<>(headers);
    
     String planetFound = restTemplate.exchange(findPlanetUri, HttpMethod.GET, entity, String.class).getBody();
    

    Another solution:

     String planetFound = restTemplate.getForObject(findPlanetUri, String.class);
    

    and

       @Bean
        public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder) {
            ClientHttpRequestInterceptor interceptor = (request, body, execution) -> {
                request.getHeaders().add("user-agent", "Application");
                return execution.execute(request, body);
            };
            return restTemplateBuilder.additionalInterceptors(interceptor).build();
        }