How to get custom messages when you use response.getStatusText() - spring

HttpClientErrorException always produces the following result for me:
HttpClientErrorException: 400 null
... and the null part is what worries me. Shouldn't this be the place where the message of the server-side exception is supposed to be?
I checked the source code of the HTTP client to see where the client-side exception is thrown. It looks like this:
throw new HttpClientErrorException(statusCode, response.getStatusText(), response.getHeaders(), getResponseBody(response), getCharset(response));
Debugging this call revealed that response.getStatusText() is null in my case.
My question is: How do you design your ResponseEntity on the server-side such that the HTTP client finds the server-side exception message in response.getStatusText() instead of null?
Here is my Exception
#ExceptionHandler({ MyCustomException.class })
public ResponseEntity<String> handleException(final HttpServletRequest
req, final MyCustomException e) {
HttpHeaders headers = new HttpHeaders();
headers.set("Content-type", "text/plain");
String body = e.toString();
return new ResponseEntity<>(body, headers, HttpStatus.BAD_REQUEST);
}

Related

Using zipOutPutStream, cannot change mediatype in exceptionhandler, when exception happens in Spring

In my post request endpoint, I want to generate ZIP File.
Here is endpoint:
public void downloadZipFile(#RequestBody final Parameters parameter, final HttpServletResponse response) throws FileReadingException, IOException {
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
response.setHeader(CONTENT_DISPOSITION, HEADER_VALUE_STR);
response.setStatus(HttpServletResponse.SC_OK);
this.generateZipServiceImpl.generateZipFile(parameter, response);
}
I throw exception when something wrong happens in
this.generateZipServiceImpl.generateZipFile(parameter, response) P.S I write files in response.getOutPutStream();
I also have global exception handler:
#ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
#ExceptionHandler(value = {FileReadingException.class, ResourceNotFoundException.class,
UncheckedIOException.class, TimebaseConnectionException.class, SecuritiesStreamCannotCopyException.class })
public ResponseEntity<String> handleInternalServerErrors() {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.TEXT_PLAIN);
return new ResponseEntity<>(INTERNAL_SERVER_ERROR_MESSAGE, headers, HttpStatus.INTERNAL_SERVER_ERROR);
}
But the result is that, if exception happens, user gets 200OK request with half-full ZIP file. I want to just return 500 SERVER_INTERNAL_ERROR. Can someone suggest me how can I do this?
In console log there is written:
WARN 40048 --- [nio-8080-exec-7]
.m.m.a.ExceptionHandlerExceptionResolver : Resolved
[com.deltix.timebaseinitializr.exceptions.SecuritiesStreamCannotCopyException:
Can't Copy securities stream files]
but ExceptionHandler's method handleInternalServeErrors() don't change MediaType to TEXT_PLAIN and don't change STATUS CODE to INTERNAL_SERVER_ERROR too, so response is MediaType.OCTET-STREAM and 200OK.
Also ExceptionHandler's other methods work correctly(for example, returns BAD_REQUEST and changes MimeType from OCTET-STREAM to TEXT_PLANI), but there I don't write anything in response.getOutPutStream() thats the difference.
So I think I want something that forces spring to clear this outputstream and change mediatype

How to handle the http response from an api call efficiently using spring boot

When we fire an api call to a 3rd party service, we can get different HTTP responses (200, 404 etc.). How can we handle them in a standard way?
private ResponseEntity<ResultHolder> responseEntity;
public ResponseEntity<ResultHolder> serviceTest(String searchText, String countryCode) {
logger.info("Service started");
String url = prepareUrl(searchText,countryCode); //custom method
HttpHeaders header = new HttpHeaders();
prepareHeader(header); //custom method
HttpEntity<String> requestEntity = new HttpEntity<String>(header);
try {
logger.info("Calling the API");
responseEntity = restClient.exchange(url,
HttpMethod.GET,
requestEntity,
ResultHolder.class);
}catch (Exception e) {
logger.error("Exception while calling the API "+ e);
//Here I am trying to get the value of response code and handle based on that
//Is this the right way to solve the problem?
if(responseEntity.getStatusCodeValue() != 200) {
responseEntity = new ResponseEntity<ResultHolder>(
HttpStatus.BAD_REQUEST);
}
}
logger.info("Service Ended");
return responseEntity;
}
What if I want to display distinct custom messages for server side errors and for user errors like 'No Internet Connection'.
Kindly help me to understand the good practises in this area.
Thank you

Handle HttpClientErrorException$BadRequest: 400 Bad Request in Cucumber RestTemplate

Hi I have written a Cucumber test case where i send a POST request with an XML body, output of that request is 400 Error with an XML body, which is expected and when i throw the request i get that too, but what i get is below:
org.springframework.web.client.HttpClientErrorException$BadRequest: 400 Bad Request
at org.springframework.web.client.HttpClientErrorException.create(HttpClientErrorException.java:79)
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:97)
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:79)
at org.springframework.web.client.ResponseErrorHandler.handleError(ResponseErrorHandler.java:63)
at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:777)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:735)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:709)
at org.springframework.web.client.RestTemplate.postForEntity(RestTemplate.java:462)
at uk.co.argos.services.order.StepDefinations.TestMethods.POSTrestTemplatewithXML(TestMethods.java:147)
at uk.co.argos.services.order.StepDefinations.StepDefs.user_hits_the_getSlot_request_with_OrderEnricher_with_and_and(StepDefs.java:118)
at ✽.Given User hits the getSlot request with OrderEnricher with "2020-40-32" and "150" and "MK92NW"(OrderEnricher_Negative.feature:5)
And my test step failes with bad request, But ideally that is my expected and i want to pass my test step & scenario, not sure how should i handle it, i have tried applying multiple things. Can anyone help please?
public static ResponseEntity<String> POSTrestTemplatewithXML(URI uri, String XMLforPOST){
ResponseEntity<String> responseEntity = null;
try {
RestTemplate restTemplate=new RestTemplate();
List<HttpMessageConverter<?>> messageConverters=new ArrayList<HttpMessageConverter<?>>();
messageConverters.add(new StringHttpMessageConverter());
restTemplate.setMessageConverters(messageConverters);
HttpHeaders headers=new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_XML);
HttpEntity<String> request=new HttpEntity<String>(XMLforPOST, headers);
responseEntity=restTemplate.postForEntity(uri, request, String.class);
}
catch (Exception e){
System.out.println("RESPONSE-" +responseEntity);
byte[] bytes = ((HttpClientErrorException.BadRequest)e).getResponseBodyAsByteArray();
assertTrue(true);
//Convert byte[] to String
String s = new String(bytes);
System.out.println(s);
e.printStackTrace();
}
return responseEntity;
}
Please update your catch method like following :
try{
//your code
} catch (HttpClientErrorException e){
//your code
}

Spring RestTemplate + Basic Authentication + Post with request Body: 500 Internal Server Error

I am looking for a working approach for Rest Client using Spring (5.x) RestTemplate with Basic Authentication + passing Request Body as HTTP Post.
NOTE: the service works fine If I hit request using postman/ other rest client, instead of a java client/ test class.
I am getting 500 Internal Server Error
org.springframework.web.client.HttpClientErrorException: 500 Internal Server Error
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:94)
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:79)
at org.springframework.web.client.ResponseErrorHandler.handleError(ResponseErrorHandler.java:63)
at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:777)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:730)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:704)
at org.springframework.web.client.RestTemplate.postForObject(RestTemplate.java:459)
at com.xxx.xxx.xxx.utils.Util.updateFlag(Util.java:125)
at com.xxx.xxx.xxx.utils.UtilsImplTest.testUpdateFlag(UtilsImplTest.java:122)
My Test class:
#Test
public void testUpdateFlag() {
Request request = new Request();
request.setUserId("aa");
request.setFlag("Y");
request.setValue("D");
Response response = null;
try {
response = util.updateFlag(request);
} catch (JsonProcessingException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
assertNotNull(response);
}
My Implementation util class: where I am setting Basic Authorization in header.
#Autowired private RestTemplate restTemplate;
private HttpHeaders getHeaders(){
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Basic " + <base64_encrypted_password>);//500
// headers.setContentType(MediaType.APPLICATION_JSON); //401
return headers;
}
public Response updateFlag(Request request) throws JsonProcessingException, URISyntaxException {
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
HttpEntity<Request> requestEntity = new HttpEntity<>(request, getHeaders());
Response response = restTemplate.postForObject(url, requestEntity, Response.class);
return response;
}
If I comment out the basic authorization line in getHeaders() method, then it throws 401 Unauthorized, which is fairly logical.
org.springframework.web.client.HttpClientErrorException: 401 Unauthorized
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:94)
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:79)
at org.springframework.web.client.ResponseErrorHandler.handleError(ResponseErrorHandler.java:63)
at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:777)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:730)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:704)
at org.springframework.web.client.RestTemplate.postForObject(RestTemplate.java:459)
at com.xxx.xxx.xxx.utils.Util.updateFlag(Util.java:125)
at com.xxx.xxx.xxx.utils.UtilsImplTest.testUpdateFlag(UtilsImplTest.java:122)
I have tried almost every option suggested over stackoverflow in similar content, unable to identify the exact root cause why setting authorization in header doesn't validate & throws 500 Internal Server Error.
I have spent quite a handful time investigating, with no luck. Appreciate any pointers.

RestTemplate - handle potential NullPointerException when response body is null

I'm writing client that calls some backend REST service. I'm sending Product object which will be saved in DB and returned in response body with generated productId.
public Long createProduct(Product product) {
RestTemplate restTemplate = new RestTemplate();
final String url = " ... ";
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<Product> productEntity = new HttpEntity<>(product, headers);
try {
ResponseEntity<Product> responseEntity = restTemplate.postForEntity(url, productEntity, Product.class);
Product product = responseEntity.getBody();
return product.getProductId();
} catch (HttpStatusCodeException e) {
logger.error("Create product failed: ", e);
throw new CustomException(e.getResponseBodyAsString(), e, e.getStatusCode().value());
}
This product.getProductId() looks like potential NullPointerException if product i.e. responseEntity.getBody() is null, should I handle it somehow?
I have looked examples over internet of using RestTemplate postFprEntity, getForEntity ... but didn't find any example that handle NPE. I suppose that if body of response cannot be set, it will be some exception thrown and status code 5xx.
Is it possible when response status code is 200, that body can be null?
Is it possible when response status code is 200, that body can be
null?
Yes, it is quite possible and totally depends on the server. Normally, some REST APIs and Spring REST Repositories will return 404 if resource is not found but better safe than sorry.
This product.getProductId() looks like potential NullPointerException
if product i.e. responseEntity.getBody() is null, should I handle it
somehow?
Of course you should.
You can check if responseEntity.hasBody() && responseEntity.getBody() != null. And from there either throw an Exception of your own or handle however you see fit.

Resources