I have the following problem...
I'm testing a service that return HTTP responses on GET requests.
My problem is that I would like to view the response even if it was an HTTP 500 / 404 or whatever response.
I would like to view that. But I can't because it throws an exception and that's it.
Is there a way to view a jersey response even if it was an error response?
My code is like this:
webResource = client.resource(url);
response = webResource.queryParams(alertParams)
.header("x-token", token).get(String.class);
So when get receives an error response from the service I wont be able to view that although the response is something like this:
{
"errCode" : "ERR002",
"errMsg" : "",
"techErrMsg" : "LoginFailureGeneric"
}
Which is a 400 Bad Request.
Thanks very much for all the help!!
This is where you need to spend some time with the docs... WebRequest#get(Class) will throw an exception when you get an HTTP error status if you are trying to parse the response as anything other than ClientResponse.
So all you need to do is change the .get(String.class) -> .get(ClientResponse.class) and you can pull the entity itself (and the status, and everything else) off of the ClientResponse object sans exceptions.
Related
I have this code, I use cxf WebClient:
WebClient client = someClient.reset();
Response response = client.post(bodyRequest);
If status code in response turns into 200 I can parse it into something like this:
CustomResponse customResponse = response.readEntity(CustomResponse.class);
And that's ok, but if status code turns to be 400 or another, response entity seems to be null, so I can't find a way to parse it into an object ResponseCodeError, like this:
ResponseCodeError responseError= response.readEntity(ResponseCodeError.class);
This will fail.
Is there a way to use cxf and parse error into Custom error class?
Thanks.
You can check the status using
int code = response.getStatus();
then you check for a code of 200 to parse the entity or throw the respective error for other codes like 400.
I use httpResp.sendError(400, "You are missing customer id") to send the response back
When I try to retrieve the message on the client side (using Rest template to call the endpoint).
However, printing the HttpClientErrorException always produces the following result for me:
HttpClientErrorException: 400 null
I see that I have HttpClientErrorException.getResponseBody has all the information about time stamp, message etc. But HttpClientErrorException.getStatusText is always empty.
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 the code I have
try{
ResponseEntity<String> responseEntity = restTemplate.exchange(uri, HttpMethod.POST, requestEntity, String.class );
System.out.println(responseEntity.getBody());
}
catch (HttpClientErrorException | HttpServerErrorException e) {
if (e.getStatusCode().equals(HttpStatus.UNAUTHORIZED) || e.getStatusCode().equals(HttpStatus.FORBIDDEN)) { System.out.println("Response Body returned:");
System.out.println(e.getResponseBodyAsString());
System.out.println("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%");
System.out.println("Status text is:");
System.out.println(e.getStatusText());
} else if (e.getStatusCode().equals(HttpStatus.BAD_REQUEST)) {
System.out.println("Response Body returned:");
System.out.println(e.getResponseBodyAsString());
System.out.println("-------------------------------");
System.out.println("Status text is:");
System.out.println(e.getStatusText());
} else {
throw e;
}
}
Sprint Boot Version: 2.1.0.RELEASE
I traced the code for how RestTemplate actually makes the calls. Basically what happens is the result of HttpClientErrorException.getStatusText() is populated by the HTTP status code's text and not your custom error message. For example, instead of just returning back error code 400, a server might return back error 400 Bad Request. Instead of status code 200, a server might return back 200 OK. If the server responds back with that optional text, that's what you'll see when you call getStatusText(). Note that that text like OK and Bad Request can't be customized by you on the server side.
This is happening because, internally, Spring is making use of SimpleClientHttpResponse.getStatusText() which is internally relying on HttpUrlConnection.getResponseMessage(). As you can see from getResponseMessage's Javadoc, the possible values returned aren't meant to be custom error messages. Note that in your case, getStatusText() is returning null because your server is just sending back a status line like 400 and not 400 Bad Request. You can also see this from the Javadoc. You can probably configure your server to send back status code text messages, but doing so still won't help you use the getStatusText() method to get your custom error message.
Consequently, the HttpClientErrorException.getStatusText() just isn't what you need. Instead, you need to continue calling getResponseBodyAsString(). However, if you know the format of the response body that is sent back from the server (since this will likely be wrapped in HTML and other stuff) you can use a regex to filter out the non-useful parts of the response message.
This is my first question here, I am a beginner in using the REST template and Spring and I apologize if I am asking simple questions.
I am trying to call a delete method from another component using the REST template.
The response I receive in POSTMAN is the following JSON:
{
"code": 100,
"message": "my message"
}
I should not be able to delete the object, so my request fails with org.springframework.web.client.HttpClientErrorException.
In the logs all I see is the:
[Request processing failed; nested exception is org.springframework.web.client.HttpClientErrorException: 400 Bad Request] with root cause...
I have searched a bit and I have seen that when try to call a rest service with restTemplate, the body of response is lost if it returns a 400.
This is the code I have used to catch the HttpClientErrorException:
try{
restTemplate.delete(url);
}
catch (HttpClientErrorException e) {
LOG.error("FM HttpClientErrorException caught");
LOG.error("FM response body : {}", e.getResponseBodyAsString());
LOG.error("FM response headers message: {}", e.getResponseHeaders().toString());
LOG.error("FM response message : {}", e.getMessage());
LOG.error("FM response status : {}", e.getStatusCode());
}
I have seen in other posts
DELETE in Spring RestTemplate with HttpEntity<List>
that one solution is to catch the exception and try to get the body of the response.
However, in my case this is always empty.
I have tried getting the response as well using the exchange from restTemplate and then catching the Exception as above, but my body is still empty:
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.DELETE, null, String.class);
LOG.info("FM response body : {}", response.getBody());
LOG.info("FM response status : {}", response.getStatusCode());
Unit test result:
Unit tes2018-06-12T15:23:02,960Z [main] ERROR c.v.b.s.impl.ServiceImpl - HttpClientErrorException caught
2018-06-12T15:23:02,960Z [main] ERROR c.v.b.s.impl.ServiceImpl - response body : []
2018-06-12T15:23:02,960Z [main] ERROR c.v.b.s.impl.ServiceImpl - response headers message: {}
2018-06-12T15:23:02,960Z [main] ERROR c.v.b.s.impl.ServiceImpl - response message : 400 Bad Request
2018-06-12T15:23:02,960Z [main] ERROR c.v.b.s.impl.ServiceImpl - response status : 400t results:
The questions are:
Can we retrieve the JSON from the response using a REST delete call?
Can we do the same using the exchange? If yes, how can we retrieve the JSON sent? I tried both and the body is always empty.
I have seen also this post:
What is the HTTP status return code for a successful DELETE statement in REST?
The 3rd question would be then:
Is it a good practice to return a JSON and say why the delete cannot succeed?
Thank you very much, any help or suggestion regarding the code or the solution is appreciated.
1,2) Yes, it is possible. Based on my own experience, I much prefer to use the REST Client that comes with the JAX-RS specification, than the one that comes with Spring.
https://docs.oracle.com/javaee/7/api/javax/ws/rs/client/package-summary.html
You can make any request you like and then just get the body, independent of the result code. Nothing gets lost.
I know this doesn't fully answer your first question, but might be helpful.
3) The best practice is to return different error codes signifying the different reasons. Was it access denied? Was the resource not available? Was there an unexpected error?
You can then document all this fairly easy using Swagger/OpenApi/etc.
These should all be enough to handle the potential exceptions. If this is still not enough, you might want to create support methods that validate that a resource can be deleted (ex: GET /api/users/{id}/isDeletable).
I'm working on a Spring REST controller, specifically on an exception handler. The exception handler works as intended and my JUnit-Test (using the Spring HTTP client) shows that the correct HTTP Status code (400) is received at the client. The HTTP client automatically translates this into a HttpClientErrorException.
However, printing the 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?
Mine currently looks like this:
#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);
}
... and I get null in the client side status text.
I must admit that I got fooled on this one. The null value printed by the Spring HttpClientErrorException is the statusText. This text is static. For example, for Status Code 404, the defined status text is "not found". There is no way to change it.
In order to receive the actual exception code, then the method suggested by Utku is exactly right. The small gotcha is that the error message needs to be extracted from HttpClientErrorException#getResponseBodyAsString(), not from HttpClientErrorException#getStatusText() like I tried.
In our running application, one of GET request starts giving response as 400 Bad Request in Internet Explorer.
On investigating , I found that GET request doesn't have queryParameters what were expected by ReST call.
As it is giving response in another browsers like Chrome, Mozilla,
how can I proceed further ?
this is Request currently being triggered--
Method of request is GET
https://XXXXXXXXX/XXX/XXXXXXXXX/XXXXXXXXX/XXXXXXXXX/XXXXXXXXX?{%22numRecords%22:1000,%22start%22:0}&_=1487576597960
and queryParameters in #QueryParam expected by ReST api are-
-numRecords
-start
I know by the above GET request, numRecords and start will not get captured by api backend.
So , is there any chance, if my GET request lack of any #QueryParam will lead to 400 Bad request response.
I found that GET request doesn't have queryParameters
You can use query parameters in GET requests as you've provided in your example like this: http://host?queryParam1=value1. however it's not possible to pass a request body as you can do for POST or PUT requests to provide JSON encoded data for example. You can work around this by adding the JSON AND URL encoded payload to a query parameter. But you endpoint explicitely has to be able to read this parameter. So you should add this parameter to your definiotn like in this example for JAX-RS:
#GET
#Path("my-endpoint")
public String request(
#PathParam("payload") JsonObject payload
) {
What you've tried is to simply pass the payload data without specifing the name of the request parameter.
Hope this helps.