How to extract HTTP status code from the RestTemplate call to a URL?
Asked Answered
L

9

68

I am using RestTemplate to make an HTTP call to our service which returns a simple JSON response. I don't need to parse that JSON at all. I just need to return whatever I am getting back from that service.

So I am mapping that to String.class and returning the actual JSON response as a string.

RestTemplate restTemplate = new RestTemplate();

String response = restTemplate.getForObject(url, String.class);

return response;

Now the question is -

I am trying to extract HTTP Status codes after hitting the URL. How can I extract HTTP Status code from the above code? Do I need to make any change into that in the way I doing it currently?

Update:-

This is what I have tried and I am able to get the response back and status code as well. But do I always need to set HttpHeaders and Entity object like below I am doing it?

    RestTemplate restTemplate = new RestTemplate();     

    //and do I need this JSON media type for my use case?
    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.APPLICATION_JSON);

    //set my entity
    HttpEntity<Object> entity = new HttpEntity<Object>(headers);

    ResponseEntity<String> out = restTemplate.exchange(url, HttpMethod.GET, entity, String.class);

    System.out.println(out.getBody());
    System.out.println(out.getStatusCode());

Couple of question - Do I need to have MediaType.APPLICATION_JSON as I am just making a call to url which returns a response back, it can return either JSON or XML or simple string.

Lucarne answered 21/4, 2014 at 20:14 Comment(0)
F
61

Use the RestTemplate#exchange(..) methods that return a ResponseEntity. This gives you access to the status line and headers (and the body obviously).

Fidelafidelas answered 21/4, 2014 at 20:23 Comment(0)
S
23

If you don´t want to leave the nice abstraction around RestTemplate.get/postForObject... methods behind like me and dislike to fiddle around with the boilerplate stuff needed when using RestTemplate.exchange... (Request- and ResponseEntity, HttpHeaders, etc), there´s another option to gain access to the HttpStatus codes.

Just surround the usual RestTemplate.get/postForObject... with a try/catch for org.springframework.web.client.HttpClientErrorException and org.springframework.web.client.HttpServerErrorException, like in this example:

try {
    return restTemplate.postForObject("http://your.url.here", "YourRequestObjectForPostBodyHere", YourResponse.class);

} catch (HttpClientErrorException | HttpServerErrorException httpClientOrServerExc) {

    if(HttpStatus.NOT_FOUND.equals(httpClientOrServerExc.getStatusCode())) {
      // your handling of "NOT FOUND" here  
      // e.g. throw new RuntimeException("Your Error Message here", httpClientOrServerExc);
    }
    else {
      // your handling of other errors here
}

The org.springframework.web.client.HttpServerErrorException is added here for the errors with a 50x.

Now you´re able to simple react to all the StatusCodes you want - except the appropriate one, that matches your HTTP method - like GET and 200, which won´t be handled as exception, as it is the matching one. But this should be straight forward, if you´re implementing/consuming RESTful services :)

Stinkweed answered 27/10, 2017 at 12:42 Comment(3)
Causing an exception just to get the response code is a pretty shady workaround... And as you wrote in you answer you can't verify a successful request 200Glyconeogenesis
I don't get your point - different HTTP codes then 200 are automatically represented by Spring via exceptions, I don't 'create' them here or something. And what do you mean by 'verify a successful request 200'? You can do anything after the restTemplate.postForObject() method call - this is exactly the representation of the 200 status, because all others will be (and are represented by Spring as said) as exceptions.Stinkweed
@Stinkweed for 1xx and 3xx also will be exception?Keister
N
11

If you want all the HTTPStatus from a RestTemplate including 4XX and 5XX, you will have to provide an ResponseErrorHandler to the restTemplate, since the default handler will throw an exception in case of 4XX or 5XX

We could do something like that :

RestTemplate restTemplate = new RestTemplate();
restTemplate.setErrorHandler(new DefaultResponseErrorHandler() {
    @Override
    public boolean hasError(HttpStatus statusCode) {
        return false;
    }
});

ResponseEntity<YourResponse> responseEntity =
    restTemplate.getForEntity("http://your.url.here", YourResponse.class);
assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.XXXX);
Northern answered 28/6, 2019 at 11:27 Comment(2)
As of spring boot 2.7.1, the default settings seem to be not throwing exception but returning a ResponseEntity wrapping the error inside.Dimmer
I don't think it's the case the "DefaultResponseErrorHandler" did not change. On RestTemplate there still all the methods that returning directly the extracted response : docs.spring.io/spring-framework/docs/current/javadoc-api/org/…Northern
P
5
private RestTemplate restTemplate = new RestTemplate();

ResponseEntity<String> response = restTemplate.exchange(url,HttpMethod.GET, requestEntity,String.class);

response contains 'body', 'headers' and 'statusCode'

to get statusCode : response.getStatusCode();

Pennington answered 27/3, 2018 at 15:52 Comment(0)
G
4

exchange(...) works but if you want less code, you can use

org.springframework.boot.test.web.client.TestRestTemplate.getForEntity(...)

which returns an Entity containing StatusCode. Change your example code to this:

RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
HttpStatus statusCode = response.getStatusCode();

To test it you can use this snippet from my unit test:

ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
assertResponseHeaderIsCorrect(response, HttpStatus.OK);

/**
 * Test the basics of the response, non-null, status expected, etc...
 */
private void assertResponseHeaderIsCorrect(ResponseEntity<String> response, HttpStatus expectedStatus) {
    assertThat(response).isNotNull();
    assertThat(response.getHeaders().getContentType()).isEqualTo(MediaType.APPLICATION_JSON_UTF8);
    assertThat(response.getStatusCode()).isEqualTo(expectedStatus);
}
Glyconeogenesis answered 5/3, 2019 at 8:18 Comment(0)
H
1

There can be some slightly trickier use cases someone might fall in (as I did). Consider the following:

Supporting a Page object in order to use it with RestTemplate and ParameterizedTypeReference:

RestPageResponse:

import java.util.ArrayList;
import java.util.List;

import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;

public class RestResponsePage<T> extends PageImpl<T>{

  private static final long serialVersionUID = 3248189030448292002L;

  public RestResponsePage(List<T> content, Pageable pageable, long total) {
    super(content, pageable, total);
  }

  public RestResponsePage(List<T> content) {
    super(content);
  }

  public RestResponsePage() {
    super(new ArrayList<T>());
  }

} 

Using ParameterizedTypeReference will yield the following:

ParameterizedTypeReference<RestResponsePage<MyObject>> responseType = 
new ParameterizedTypeReference<RestResponsePage<MyObject>>() {};
HttpEntity<RestResponsePage<MyObject>> response = restTemplate.exchange(oauthUrl, HttpMethod.GET, entity, responseType);

Calling #exchange:

HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.MULTIPART_FORM_DATA);
            HttpEntity<?> entity = new HttpEntity<>(headers);

response = restTemplate.exchange("localhost:8080/example", HttpMethod.GET, entity, responseType);

Now here is the "tricky" part.

Trying to call exchange's getStatusCode will be impossible because the compiler, unfortunately, will be unaware of the "intended" type of response.

That is because generics are implemented via type erasure which removes all information regarding generic types during compilation (read more - source)

((ResponseEntity<RestResponsePage<MyObject>>) response).getStatusCode()

In this case, you have to explicitly cast the variable to the desired Class to get the statusCode (and/or other attributes)!

Hardnosed answered 5/7, 2017 at 20:7 Comment(0)
P
1

Putting this much of code is enough for me HttpStatus statusCode = ((ResponseEntity<Object>) responseOfEsoft).getStatusCode();

Phlebotomy answered 17/4, 2019 at 11:21 Comment(0)
K
1

You can use this solution

RestTemplate restTemplate = new RestTemplate();

final String baseUrl = "http://www.myexampleurl.com";
URI uri = new URI(baseUrl);

ResponseEntity<String> result = restTemplate.getForEntity(uri, String.class);

//get status code
int statuCode = result.getStatusCodeValue();
Kamat answered 22/4, 2020 at 16:3 Comment(0)
M
1

Was able to solve this through:
HttpEntity<Object> entity = restTemplate.getForEntity(uri, Object.class);

ResponseEntity<String> result = restTemplate.exchange(uri, HttpMethod.GET, entity, String.class);

System.out.println(result.getStatusCode());

Modeling answered 8/10, 2021 at 9:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.