I have a REST endpoint which call another API which take a while to process and returning 504 error when I verify through Rest client (Insomnia). But in my service I see this transaction as success 200 not 504.
Below is how my code snippet:
public ResponseEntity<Customer> processResponse(Customer customer, String restUri) {
ResponseEntity<Customer> response;
String customerJson = null;
try {
RestTemplate restTemplate = restTemplateBuilder.basicAuthorization(userName, password).build();
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<Customer> entity = new HttpEntity<>(customer, headers);
CustomerJson = jacksonUtil.toJSON(customer);
response = restTemplate.exchange(restUri, HttpMethod.PUT, entity, Customer.class);
if (response.getStatusCode().is2xxSuccessful()) {
logger.info("Return success from the server");
} else {
logger.error("Error while getting the response from the server");
}
} catch (Exception ex) {
ex.printStackTrace();
throw ex;
}
return response;
}
What am I missing here? Why its not executing the else block?
Thanks in advance.
Your method seems to be returning null response in case of error. Can you check if you have done any handling in caller and passing 200 from controller layer itself.
Related
I want to implement CloudHealth API in my Spring Boot application. I want to fetch report of particular client. I have a dropdown where logged in user select reports and that report will be directly fetched from CloudHealth platform. I want to do that thing in my application. I want to generate JSON response of custom report. I followed API documentation available at https://apidocs.cloudhealthtech.com/#reporting_data-for-custom-report
but I am getting 404 Not Found: "{"error":"Record with id not found."}"
This is the code written in my service class:
public String getCustomReportData(String reportId) {
ResponseEntity<String> responseEntity = null;
String response = null;
try {
final String uri = "https://chapi.cloudhealthtech.com/olap_reports/custom/"+reportId;
RestTemplate restTemplate = new RestTemplate();
HttpHeaders header = new HttpHeaders();
header.set(HttpHeaders.AUTHORIZATION, "Bearer my-api-key");
header.set(HttpHeaders.ACCEPT,"application/json");
HttpEntity<String> requestEntity = new HttpEntity<String>("body",header);
responseEntity = restTemplate.exchange(uri, HttpMethod.GET, requestEntity, String.class);
response = responseEntity.getBody();
} catch (Exception e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
return response;
}
This is main endpoint in my restcontoller:
#RequestMapping(value = {"/custom_report/{report_id}"}, method = {RequestMethod.GET, RequestMethod.POST}, produces = {MediaType.APPLICATION_JSON_VALUE})
public ResponseEntity<Object> getCustomCloudHealthReports(HttpServletRequest request,#PathVariable("report_id") String reportId){
try {
String response = standardReportService.getCustomReportData(reportId);
return new ResponseEntity<Object>(response, HttpStatus.OK);
} catch (Exception e) {
System.out.println(e.getMessage());
e.printStackTrace();
return new ResponseEntity<Object>("Please try again later", HttpStatus.INTERNAL_SERVER_ERROR);
}
}
I Use the Supplier in my code to call restTemplate and make the custom Message when have exception..
But, im my message, i need get information by my requestCall, But when i cast the request the java thow error
...
My code:
public void execute() {
HttpHeaders headers = buildDefaultHeaders();
UriBuilder uri = UriBuilder.fromUri(wdd3dGatewayEndpoint + API_URL);
HttpEntity request = new HttpEntity(headers);
this.executeRequest(() -> restTemplate.exchange(uri.build(), HttpMethod.DELETE, request, Void.class));
}
My Supplier
protected ResponseEntity executeRequest(Supplier<ResponseEntity> request) {
try {
ResponseEntity response = request.get();
updateSessionToken(response);
return response;
} catch (HttpClientErrorException | HttpServerErrorException e) {
String msg = "WDD3D-Error in service communication<br>" + e.getResponseBodyAsString();
throw new MaestroException(msg);
}
}
Now, i try cast to get URL...
protected ResponseEntity executeRequest(Supplier<ResponseEntity> request) {
try {
ResponseEntity response = request.get();
updateSessionToken(response);
return response;
} catch (HttpClientErrorException | HttpServerErrorException e) {
//THROW EXEPTION HERE... PLEASE HELP...
RequestEntity requestEntity = (RequestEntity) request;
String url = requestEntity.getUrl().toString();
String msg = "WDD3D-Error in service communication<br>" + e.getResponseBodyAsString();
throw new MaestroException(msg);
}
}]
You should use the get() method of the Supplier, see more in the docs.
RequestEntity requestEntity = (RequestEntity) request;
You are trying to cast a Supplier<ResponseEntity> to a RequestEntity.
These are two very different classes and such a cast will never work.
Maybe you want to call request.get() and get the URL from the ResponseEntity that you have.
Tell me if it works for you in the comments or we need to debug further ?
The only thing you are trying to get from the RequestEntity is the URL, which you can't get from the Supplier<ResponseEntity> since it is not a RequestEntity, so why not just pass the URL as another parameter to executeRequest? Then it would have the additional information it needs to log the error.
I have a Spring Boot application written in Java that is a REST API. This service (Svc A) calls a REST API service (Svc B) with is also a Spring Boot Application written in Java. Svc B returns a 404 status code when no data was found. I need to change this response to a 200 status code and return an empty response object. I am not sure if or how to do this.
I can catch the error and determine if the 404 is this no data found error. However, I don't know how to change the response to a 200 empty response.
I am using a FeignClient to call the service. This is the error code that catches the 404:
#Component
public class FeignErrorDecoder implements ErrorDecoder {
Logger logger = LoggerFactory.getLogger(this.getClass());
#Override
public Exception decode(String methodKey, Response response) {
Reader reader = null;
String messageText = null;
switch (response.status()){
case 400:
logger.error("Status code " + response.status() + ", methodKey = " + methodKey);
case 404:
{
logger.error("Error took place when using Feign client to send HTTP Request. Status code " + response.status() + ", methodKey = " + methodKey);
try {
reader = response.body().asReader();
//Easy way to read the stream and get a String object
String result = CharStreams.toString(reader);
logger.error("RESPONSE BODY: " + result);
ObjectMapper mapper = new ObjectMapper();
//just in case you missed an attribute in the Pojo
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
//init the Pojo
ExceptionMessage exceptionMessage = mapper.readValue(result,
ExceptionMessage.class);
messageText = exceptionMessage.getMessage();
logger.info("message: " + messageText);
} catch(IOException ex) {
logger.error(ex.getMessage());
}
finally {
try {
if (reader != null)
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return new ResponseStatusException(HttpStatus.valueOf(200), messageText);
}
default:
return new Exception(response.reason());
}
}
}
I can change the status code to a 200 and it returns a 200 but I need to the response to have an empty response object.
The above code will return this response body of an error response object:
{
"statusCd" : "200",
"message" : "The Location not found for given Location Number and Facility Type Code",
"detailDesc" : "The Location not found for given Location Number and Facility Type Code. Error Timestamp : 2020-01-31 18:19:13"
}
I need it to return a response body like this:
200 - Empty Response
{
"facilityNumber": "923",
"facilityTimeZone": null,
"facilityAbbr": null,
"scheduledOperations": []
}
In case 404 just try
return new ResponseStatusException(HttpStatus.valueOf(200));
For anyone that has to do something this crazy...here is my solution:
Removed the FeignErrorCode file.
Added an exception to ControllerAdvice class like this:
#ExceptionHandler(FeignException.class)
public ResponseEntity<?> handleFeignException(FeignException fe, WebRequest request) {
ErrorDetails errorDetails = new ErrorDetails(new Date(), HttpStatus.valueOf(fe.status()), fe.getMessage(), request.getDescription(false));
String response = fe.contentUTF8();
if(response != null) {
ScheduledOperationsViewResponse scheduledOperationsViewResponse = new ScheduledOperationsViewResponse();
if (response.contains("Scheduled") || response.contains("Location")) {
HttpHeaders headers = new HttpHeaders();
scheduledOperationsViewResponse.setFacilityNumber(request.getParameter("facilityNumber"));
return new ResponseEntity<ScheduledOperationsViewResponse>(scheduledOperationsViewResponse, headers, HttpStatus.OK);
}
}
return new ResponseEntity<>(errorDetails, errorDetails.getStatus());
}
In my Android app I try to make a POST via restTemplate.postForEntity() but the first time I try to post the data I get a 400 error. After my timetrigger sync-method try to post the data again it works and I get 200. I don't think it's a backend problem, because I did a couple requests via Swagger and Postman on the same interface and all of them worked without a problem.
This is the error I get:
POST request for "<url>" resulted in 400 (); invoking error handler
org.springframework.web.client.HttpClientErrorException: 400
This is what I see at the postForEntity() when I'm debugging:
'java.lang.NullPointerException' Cannot evaluate org.springframework.http.ResponseEntity.toString()
This is the code:
public ResponseEntity<ArrayList> postServiceData(List<BasicService> attributes) {
HttpStatus status = null;
ResponseEntity<ArrayList> chargerServiceResponse = new ResponseEntity<ArrayList>(status);
try {
RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
HttpEntity<?> entity = RestServiceUtils.getHttpEntity(attributes, context);
chargerServiceResponse = restTemplate.postForEntity(url, entity, ArrayList.class);
SynchronisationStorage synchronisationStorage = new SynchronisationStorage(context);
synchronisationStorage.updateLastSynchronisationDate();
loggingStorageDbHelper.logSuccess(R.string.logging_save_send_charger_service_to_backend, 1000);
} catch (HttpClientErrorException e) {
/* do stuff*/
}
}
To set the body and token:
#NonNull
public static HttpEntity<?> getHttpEntity(List attributes, Context context) {
HttpHeaders headers = new HttpHeaders();
try {
headers.set(ServiceAppConstants.HEADER_ACCEPT, ServiceAppConstants.MEDIATYPE_JSON);
UserStorage userStorage = new UserStorage(context);
String token = userStorage.getJsonWebToken();
headers.set(ServiceAppConstants.HEADER_SECURITY_TOKEN, token);
}catch (Exception ex){
Log.e(RestServiceUtils.class.getName(), "Exception ocurred while trying to set token to header", ex);
}
return new HttpEntity<Object>(attributes, headers);
}
i'm sending data to a server and i want to receive the HTTP response status in order to check this status and provide the appropriate view
#RequestMapping(method = RequestMethod.POST)
public String Login(#ModelAttribute("Attribute") Login login, Model model,HttpServletRequest request) {
// Prepare acceptable media type
ArrayList<MediaType> acceptableMediaTypes = new ArrayList<MediaType>();
acceptableMediaTypes.add(MediaType.APPLICATION_XML);
// Prepare header
HttpHeaders headers = new HttpHeaders();
headers.setAccept(acceptableMediaTypes);
HttpEntity<Login> entity = new HttpEntity<Login>(login, headers);
// Send the request as POST
try {
ResponseEntity<Login> result = restTemplate.exchange("http://www.../user/login/",
HttpMethod.POST, entity, Login.class);
} catch (Exception e) {
}
//here i want to check the received status
if(status=="OK"){
return "login"
}
else
return "redirect:/home";
}
What's wrong with:
HttpStatus status = result.getStatusCode();
if(status == HttpStatus.OK)
See: ResponseEntity JavaDoc.
BTW you should not compare strings using == operator like here:
status=="OK"
Instead use the following idiom:
"OK".equals(status)
Also method names in Java tend to start with lower case.
The ResponseEntity object contains the HTTP status code.
// Prepare acceptable media type
ArrayList<MediaType> acceptableMediaTypes = new ArrayList<MediaType>();
acceptableMediaTypes.add(MediaType.APPLICATION_XML);
// Prepare header
HttpHeaders headers = new HttpHeaders();
headers.setAccept(acceptableMediaTypes);
HttpEntity<Login> entity = new HttpEntity<Login>(login, headers);
// Create status variable outside of try-catch block
HttpStatus statusCode = null;
// Send the request as POST
try {
ResponseEntity<Login> result = restTemplate.exchange("http://www.../user/login/",
HttpMethod.POST, entity, Login.class);
// Retrieve status code from ResponseEntity
statusCode = result.getStatusCode();
} catch (Exception e) {
}
// Check if status code is OK
if (statusCode == HttpStatus.OK) {
return "login"
}
else
return "redirect:/home";