Below is my response from one of the server call from my Spring Boot app,
String result = restTemplate.exchange(url, HttpMethod.GET, entity, String.class).getBody();
Then I am returning to client like,
return ResponseEntity.ok().body(result);
In postman I see json is printed with many \" rather pretty formated.
Is there I need to change in response side to see pretty formatted output in Postman?
Sample Postman output:
"{\"records\":[{\"pkg_name\":\"com.company.app\",\"start_time\":1580307656040,\"update_time\":12345,\"min\":0.0,\"create_time\":1580307714254,\"time_offset\":21600000,\"datauuid\":\"xyz\",\"max\":0.0,\"heart_beat_count\":1,\"end_time\":1580307656040,\"heart_rate\":91.0,\"deviceuuid\":\"abc\"}]}" ...
Expected output: Pretty formatted without \"
It seems to me that String result = restTemplate.exchange(url, HttpMethod.GET, entity, String.class).getBody(); returns double encoded json string. to unescape and get normal json
String unwrappedJSON = objectMapper.readValue(result, String.class);
return ResponseEntity.ok().body(unwrappedJSON);
EDIT
if result is normal json and not double escaped than you can try:
JsonNode result = restTemplate.exchange(url, HttpMethod.GET, entity, JsonNode.class).getBody();
return ResponseEntity.ok().body(result);
The best approach is to create bean and deserializate this String to it.
After it you will have structured object with all benefits. (For example pretty toString method)
Related
The url-string contains a back-slash character that needs to be encoded. The url string is as follows.
String folder = "\\Foo\\Bar\\"; // some folder search path.
String urlString= "http://localhost:8081/certificates/?mypath=%5CFoo%5CBar%5C" // (after encoding)
Here I use Spring RestTemplate to do a GET request. I setup a mock-server to examine the request in detail (mock server setup using Mulesoft, if u must know!).
ResponseEntity<String> responseEntity = api.exchange(urlString, HttpMethod.GET, new HttpEntity<>(new HttpHeaders()), String.class);
Here I use plain vanilla Java URLConnection to perform the request. Attached image with detailed request snapshot.
// 2. Plain vanilla java URLConnection. "result.toString()" has certificate match.
StringBuilder result = new StringBuilder();
URL url = new URL(urlString);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestProperty("X-Venafi-Api-Key", apiKey);
conn.setRequestMethod("GET");
BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line;
while ((line = rd.readLine()) != null) {
result.append(line);
}
rd.close();
System.out.println(result.toString());
In the images, you can see that the queryString value is different for these two requests. One of them shows \\ while the other shows %5C, although the parsed parameter value for myPath is still the same.
I am having to deal with an api that seems to work if-and-only-if the queryString looks like the former (i.e. "\\"). Why does the parsed queryString for Spring show "%5C" while this value shows double-backslash for requests originating from plain Java, curl, and even a simple browser?
What baffles me EVEN more, is that just about everything about the two HTTP Requests are IDENTICAL! And yet, why does the queryString/requestUri parse differently for these two requests? Shouldn't it be that a HTTP GET method is completely defined by its header contents and the requestUri? What am I missing to capture in these two GET requests?
Lots of questions. Spent an entire day, but at least I could verify that the way the requestUri/queryString is parsed seems to align with how the remote api-server responds.
Thanks.
Did some digging around the following morning. Turn out, with
ResponseEntity<String> responseEntity = api.exchange(urlString, HttpMethod.GET, new HttpEntity<>(new HttpHeaders()), String.class);
You should NOT have the "urlString" already encoded. The 'exchange' method does that encoding for you under-the-hood.
I can do this for POST
ResponseEntity<ResponseMessage> response = restTemplate.postForEntity(URL, animal, ResponseMessage.class);
return response.getBody();
But why there is no putForEntity for PUT? There is just resTemplate.put(...
How do I do it for 'PUT' request.
You can use:
restTemplate.exchange(url, HttpMethod.PUT, requestEntity, ...)
Here is the link to the documentation of this method.
You can use PUT instead, reason why putForEntity is not available because as per standard PUT will not return a response body but 201 or 200 in most of the cases.
I am currently testing one of my services with Spring boot test.The service exports all user data and produces a CSV or PDF after successful completion. A file is downloade in browser.
Below is the code i have wrote in my test class
MvcResult result = MockMvc.perform(post("/api/user-accounts/export").param("query","id=='123'")
.contentType(MediaType.APPLICATION_JSON_VALUE)
.accept(MediaType.APPLICATION_PDF_VALUE)
.content(TestUtil.convertObjectToJsonBytes(userObjectDTO)))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_PDF_VALUE))
.andReturn();
String content = result.getResponse().getContentAsString(); // verify the response string.
Below is my resource class code (call comes to this place)-
#PostMapping("/user-accounts/export")
#Timed
public ResponseEntity<byte[]> exportAllUsers(#RequestParam Optional<String> query, #ApiParam Pageable pageable,
#RequestBody UserObjectDTO userObjectDTO) {
HttpHeaders headers = new HttpHeaders();
.
.
.
return new ResponseEntity<>(outputContents, headers, HttpStatus.OK);
}
While I debug my service, and place debug just before the exit, I get content Type as 'application/pdf' and status as 200.I have tried to replicate the same content type in my test case. Somehow it always throws below error during execution -
java.lang.AssertionError: Status
Expected :200
Actual :406
I would like to know, how should i inspect my response (ResponseEntity). Also what should be the desired content-type for response.
You have problem some where else. It appears that an exception/error occurred as noted by application/problem+json content type. This is probably set in the exception handler. As your client is only expecting application/pdf 406 is returned.
You can add a test case to read the error details to know what exactly the error is.
Something like
MvcResult result = MockMvc.perform(post("/api/user-accounts/export").param("query","id=='123'")
.contentType(MediaType.APPLICATION_JSON_VALUE)
.accept(MediaType.APPLICATION_PROBLEM_JSON_VALUE)
.content(TestUtil.convertObjectToJsonBytes(userObjectDTO)))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_PROBLEM_JSON_VALUE))
.andReturn();
String content = result.getResponse().getContentAsString(); // This should show you what the error is and you can adjust your code accordingly.
Going forward if you are expecting the error you can change the accept type to include both pdf and problem json type.
Note - This behaviors is dependent on the spring web mvc version you have.
The latest spring mvc version takes into account the content type header set in the response entity and ignores what is provided in the accept header and parses the response to format possible. So the same test you have will not return 406 code instead would return the content with application json problem content type.
I found the answer with help of #veeram and came to understand that my configuration for MappingJackson2HttpMessageConverter were lacking as per my requirement. I override its default supported Mediatype and it resolved the issue.
Default Supported -
implication/json
application*/json
Code change done to fix this case -
#Autowired
private MappingJackson2HttpMessageConverter jacksonMessageConverter;
List<MediaType> mediaTypes = new ArrayList<>();
mediaTypes.add(MediaType.ALL);
jacksonMessageConverter.setSupportedMediaTypes(mediaTypes);
406 means your client is asking for a contentType (probably pdf) that the server doesn't think it can provide.
I'm guessing the reason your code is working when you debug is that your rest client is not adding the ACCEPT header that asks for a pdf like the test code is.
To fix the issue, add to your #PostMapping annotation produces = MediaType.APPLICATION_PDF_VALUE see https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/bind/annotation/PostMapping.html#produces--
I don't know why my code is not working, I've tried with Postman and works fine:
But with RestTemplate I can´t get a response while it´s using the same endpoint... .
ResponseEntity<String> responseMS = template.exchange(notificationRestService, HttpMethod.DELETE, new HttpEntity<NotificationRestDTO[]>(arrNotif), String.class);
I've tried with List instead Array[]
When i made a PUT request it´s works fine but with one object:
ResponseEntity<String> responseMS = template.exchange(notificationRestService, HttpMethod.PUT, new HttpEntity<NotificationRestDTO>(notificationDTO), String.class);
Any help?? Thanks!!
From the comments it became clear that you're expecting it to return a 400 Bad Request response. RestTemplate will see these as "client errors" and it will throw a HttpClientErrorException.
If you want to handle cases like this, you should catch this exception, for example:
try {
ResponseEntity<String> responseMS = template.exchange(notificationRestService, HttpMethod.DELETE, new HttpEntity<NotificationRestDTO[]>(arrNotif), String.class);
} catch (HttpClientErrorException ex) {
String message = ex.getResponseBodyAsString();
}
In this case (since you expect a String), you can use the getResponseBodyAsString() method.
The ResponseEntity will only contain the data in case your request can be executed successfully (2xx status code, like 200, 204, ...). So, if you only expect a message to be returned if the request was not successfully, you can actually do what Mouad mentioned in the comments and you can use the delete() method of the RestTemplate.
I can easily get the expected JSON response if I send the following get request from my browser:
http://www.bookandwalk.hu/api/AdminTransactionList?password=XXX&begindate=2016-04-30&enddate=2016-10-12&corpusid=HUBW
I tried to use SPRING BOOT 1.4 to create a small demo app to see how rest calls work in Spring.
So I created a POJO representing my domain object and I requested the list of domain objects by the following method invocation:
String startDate=new SimpleDateFormat("yyyy-MM-dd").format(start.getTime());
String endDate=new SimpleDateFormat("yyyy-MM-dd").format(end.getTime());
UriComponents uri=UriComponentsBuilder.newInstance().scheme("http").host("www.bookandwalk.hu").path("/api/AdminTransactionList").queryParam("password","xxx").queryParam("begindate",startDate).queryParam("enddate",endDate).queryParam("corpusid","HUBW").build().encode();
LOG.log(Level.INFO,"{0} were called as a rest call",uri.toString());
ResponseEntity<List<BandWTransaction>> transResponse =
restTemplate.exchange(uri.toString(),
HttpMethod.GET, null, new ParameterizedTypeReference<List<BandWTransaction>>() {
});
List<BandWTransaction> transactions = transResponse.getBody();
I got the following exception:
org.springframework.web.client.HttpClientErrorException: 404 Not Found
As I logged the uri.toString(), I copied it to my browser to double check the is there any typos in my uri but it was working without any failure.
Does Anybody have idea why the same string works from the browser but not from the code?
It seems that you should specify a user agent header in the request for this webapp. Use a HttpEntity object to set this header.
final HttpHeaders headers = new HttpHeaders();
headers.set("User-Agent", "eltabo");
final HttpEntity<String> entity = new HttpEntity<String>(headers);
ResponseEntity<List<BandWTransaction>> transResponse =
restTemplate.exchange(uri.toString(),
HttpMethod.GET, entity,
new ParameterizedTypeReference<List<BandWTransaction>>() {});
Hope it helps.