equivalent class RetrofitError in retrofit 2.0 - java

I'm looking for equivalent class RetrofitError in retrofit 2.0
I do sync call and need status code, headers, body, etc. For async call it is easy but how to do it with async?
My code:
try {
Response<User> execute = call.execute();
} catch (RetroFitError e)
{
call.getResponse(); //Response object containing status code, headers, body, etc.
}

Related

OKHTTP GET and POST request return empty body message

I want to a upload file on my server and I've decided to try OKHTTP instead of my current method which is based on android own HTTP implementation and AsyncTask.
Anyway, I used OKHTTP and its asynchronous implementation (from its own recipes) but it returns an empty message (the request code is ok, the message is empty) in both GET and POST methods.
Did I implement it wrong or is there anything else remained that I did not considered? In the meantime, I couldn't find a similar case except this which says used AsyncTask.
Here's the code:
Request request;
Response response;
private final OkHttpClient client = new OkHttpClient();
private static final String postman_url = "https://postman-echo.com/get?foo1=bar1&foo2=bar2";
String message_body;
public void Get_Synchronous() throws IOException
{
request = new Request.Builder()
.url(postman_url)
.build();
Call call = client.newCall(request);
response = call.execute();
message_body = response.toString();
//assertThat(response.code(), equalTo(200));
}
public void Get_Asynchronous()
{
request = new Request.Builder()
.url(postman_url)
.build();
Call call = client.newCall(request);
call.enqueue(new Callback() {
public void onResponse(Call call, Response response)
throws IOException
{
message_body = response.toString();
}
public void onFailure(Call call, IOException e)
{
}
});
}
Edit:
I catch the log on response:
onResponse: Response{protocol=h2, code=200, message=, url=https://postman-echo.com/get?foo1=bar1&foo2=bar2}
OK, for anyone who wants to receive an string from a call, response and response.messgage() don't provide that. To catch the response from your provider, you just need to call response.body().string() inside onResponse which returns the message inside your request.
But after all, Retrofit is a better choice if you want to receive a JSON file using
.addConverterFactory(GsonConverterFactory.create(gson)).
If you still want to receive an string just use .addConverterFactory(ScalarsConverterFactory.create()) as explained here.

How do I log out the body of a failed response to a Spring WebFlux WebClient request while returning the response to the caller?

I'm very new to reactive programming and I have a REST service that takes a request and then calls to another API using the WebFlux WebClient. When the API responds with a 4xx or 5xx response, I want to log the response body in my service, and then pass on the response to the caller. I've found a number of ways to handle logging the response, but they generally return Mono.error to the caller, which is not what I want to do. I have this almost working, but when I make the request to my service, while I get back the 4xx code that the API returned, my client just hangs waiting for the body of the response, and the service never seems to complete processing the stream. I'm using Spring Boot version 2.2.4.RELEASE.
Here's what I've got:
Controller:
#PostMapping(path = "create-order")
public Mono<ResponseEntity<OrderResponse>> createOrder(#Valid #RequestBody CreateOrderRequest createOrderRequest) {
return orderService.createOrder(createOrderRequest);
}
Service:
public Mono<ResponseEntity<OrderResponse>> createOrder(CreateOrderRequest createOrderRequest) {
return this.webClient
.mutate()
.filter(OrderService.errorHandlingFilter(ORDERS_URI, createOrderRequest))
.build()
.post()
.uri(ORDERS_URI)
.contentType(MediaType.APPLICATION_JSON)
.bodyValue(createOrderRequest)
.exchange()
.flatMap(response -> response.toEntity(OrderResponse.class));
}
public static ExchangeFilterFunction errorHandlingFilter(String uri, CreateOrderRequest request) {
return ExchangeFilterFunction.ofResponseProcessor(clientResponse -> {
if (clientResponse.statusCode() != null && (clientResponse.statusCode().is5xxServerError() || clientResponse.statusCode().is4xxClientError())) {
return clientResponse.bodyToMono(String.class)
.flatMap(errorBody -> OrderService.logResponseError(clientResponse, uri, request, errorBody));
} else {
return Mono.just(clientResponse);
}
});
}
static Mono<ClientResponse> logResponseError(ClientResponse response, String attemptedUri, CreateOrderRequest orderRequest, String responseBody) {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
try {
log.error("Response code {} received when attempting to hit {}, request:{}, response:{}",
response.rawStatusCode(), attemptedUri, objectMapper.writeValueAsString(orderRequest),
responseBody);
} catch (JsonProcessingException e) {
log.error("Error attempting to serialize request object when reporting on error for request to {}, with code:{} and response:{}",
attemptedUri, response.rawStatusCode(), responseBody);
}
return Mono.just(response);
}
As you can see, I'm simply trying to return a Mono of the original response from the logResponseError method. For my testing, I'm submitting a body with a bad element which results in a 422 Unprocessable Entity response from the ORDERS_URI endpoint in the API I'm calling. But for some reason, while the client that called the create-order endpoint receives the 422, it never receives the body. If I change the return in the logResponseError method to be
return Mono.error(new Exception("Some error"));
I receive a 500 at the client, and the request completes. If anyone knows why it won't complete when I try to send back the response itself, I would love to know what I'm doing wrong.
Can't have your cake and eat it too!
The issue here is that you are trying to consume the body of the response twice, which is not allowed. Normally you would get an error for doing so.
Once in
return clientResponse.bodyToMono(String.class)
but also in
response.toEntity(OrderResponse.class)
which actually runs
#Override
public <T> Mono<ResponseEntity<T>> toEntity(Class<T> bodyType) {
return WebClientUtils.toEntity(this, bodyToMono(bodyType));
}
So one solution would be to process the ResponseEntity instead of the ClientResponse as follows since you don't actually want to do any reactive stuff with the body
public Mono<ResponseEntity<OrderResponse>> createOrder(CreateOrderRequest createOrderRequest) {
return this.webClient
//no need for mutate unless you already have things specified in
//base webclient?
.post()
.uri(ORDERS_URI)
.contentType(MediaType.APPLICATION_JSON)
.bodyValue(createOrderRequest)
.exchange()
//Here you map the response to an entity first
.flatMap(response -> response.toEntity(OrderResponse.class))
//Then run the errorHandler to do whatever
//Use doOnNext since there isn't any reason to return anything
.doOnNext(response ->
errorHandler(ORDERS_URI,createOrderRequest,response));
}
//Void doesn't need to return
public static void errorHandler(String uri, CreateOrderRequest request,ResponseEntity<?> response) {
if( response.getStatusCode().is5xxServerError()
|| response.getStatusCode().is4xxClientError())
//run log method if 500 or 400
OrderService.logResponseError(response, uri, request);
}
//No need for redundant final param as already in response
static void logResponseError(ResponseEntity<?> response, String attemptedUri, CreateOrderRequest orderRequest) {
//Do the log stuff
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
try {
log.error("Response code {} received when attempting to hit {}, request:{}, response:{}",
response.getStatusCodeValue(), attemptedUri, objectMapper.writeValueAsString(orderRequest),
response.getBody());
} catch (JsonProcessingException e) {
log.error("Error attempting to serialize request object when reporting on error for request to {}, with code:{} and response:{}",
attemptedUri, response.getStatusCodeValue(), response.getBody());
}
}
Note that there isn't really a reason to use the ExchangeFilter since you aren't actually doing any filtering, just performing an action based off the response

Set header in retrofit http post request

I have a retrofit interface (kotlin):
interface Api {
#POST("updates")
fun getDetails(#Header("Authorization") token: Token,
#Body body: RequestBody): Single<ResponseObject>
}
When I call it like this (in java),
List<String> apps = Arrays.asList("app1", "app2");
JSONObject jsonObject = new JSONObject();
RequestBody requestBody;
try {
jsonObject.put("apps", new JSONArray(apps));
}
catch(JSONException e) {
e.printStackTrace();
}
requestBody = RequestBody.create(jsonObject.toString(), MediaType.get("application/json"));
api.getDetails(token, requestBody); // works
It works and returns the proper data.
My problem is that I don't want to create a new RequestBody object for each call, so instead of receiving a RequestBody, I want my interface to receive the JSON Object. When I try this however,
interface Api {
#POST("updates")
fun getDetails(#Header("Authorization") token: Token,
#Header("Content-Type") type: String,
#Body body: JSONObject): Single<ResponseObject>
}
api.getDetails(token, "application/json", jsonObject); // does not work
it returns with a retrofit2.adapter.rxjava2.HttpException: HTTP 400 error.
How do I make this http call with just the JSONObject? I think there may be something wrong with how I am specifying the Content-Type, but I can't figure it out.

RestTemplate get body with ResourceAccessException

I'm sending API and receiving status code 400 with body I need to parse
When working with RestTemplate I failed to parse response:
try {
ResponseEntity<ResponseVO> response = restTemplate.exchange(uri, HttpMethod.POST, request, ResponseVO.class);
} catch(HttpStatusCodeException e){
// not catch
String errorpayload = e.getResponseBodyAsString();
} catch (RestClientException e) {
// catch without body
}
Also With adding error handlers (default and specific) suggested I always get a ResourceAccessException which isn't catch by HttpClientErrorException and doesn't include body/headers data
How can I still get body/headers in that case? must I use alternatives to RestTemplate ?
Moreover, how can I return to context of request when I'm in caught exception inside handleError:
public void handleError(ClientHttpResponse response) throws IOException {
The issue I was using interceptor which read my body already,
Changed RestTemplate to using BufferingClientHttpRequestFactory I can now re-read my body
RestTemplate restTemplate = new RestTemplate(new BufferingClientHttpRequestFactory(new HttpComponentsClientHttpRequestFactory()));
Using this wrapper allows for multiple reads of the response body.

What is the best way to send a simple error response message from the server to calling jQuery ajax method (e.g., responseText)?

what I'm trying to do...
I want to send a response message back to the calling jQuery AJAX method, that I can then use to create a warning popup message.
I tried using the HttpServletResponse method:
sendError(int sc, java.lang.String msg)
the problem...
Unfortunately, this method wraps the "msg" string value within a larger HTML string - which is apparently meant to be used as content for a standalone error page.
--I was hoping to just obtain the message string itself (i.e., using a jquery object method - e.g., "jqXHR").
How should I best accomplish this? (I.e., get the message back to the success/failure method without the HTML "wrapper")
...the java server snippet...
-
-
-
private List<MyDTO> performSearch(HttpSession session, HttpServletResponse resp)
{
try
{
// (code to inspect searchString, etc.)
//...forcing error for this test...
throw new Exception("bad request yaddah...yaddah...yaddah...");
}
catch (Exception e)
{
try
{
resp.sendError(HttpServletResponse.SC_NOT_FOUND, e.getMessage());
}
catch (Exception e)
{
e.printStackTrace();
}
}
return null;
}
-
-
-
...the JQuery client snippet...
-
-
-
$.ajax({
type: "POST",
url: searchurl,
data: "searchString=" + searchString,
async: true,
success: function(jqXHR) {
alert("success");
},
error: function(jqXHR) {
alert("Error - bad search string used:" + jqXHR.responseText);
}
});
-
-
-
NOTE: Doing something like below, seems to work okay, but, I want to know if there is a better way to send a simple message string back to the ajax call ...
-
-
-
private List<MyDTO> performSearch(HttpSession session, HttpServletResponse resp)
{
try
{
// (inspect searchString, etc.)
//...forcing error for this test...
throw new Exception("bad request yaddah...yaddah...yaddah...");
}
catch (Exception e)
{
try
{
resp.setStatus(HttpServletResponse.SC_NOT_ACCEPTABLE);
resp.getWriter().write(e.getMessage());
resp.flushBuffer();
}
catch (Exception ex)
{
e.printStackTrace();
}
}
return null;
}
-
-
-
What is the simplest/best way to accomplish what I am trying to do?
Thanks for any help!!!
I don't know if you still need an answer after 3 years, but I'm working on a project and need to do the same thing. I use ResponseEntity as a return type for the methods in my Controller. It has a HttpStatus code (which will fire the success/error function from jQuery/AJAX) and a body (without the wrapper thing). You can rewrite your controller method like this:
Controller
private ResponseEntity performSearch(HttpSession session)
{
try
{
// (inspect searchString, etc.)
//...forcing error for this test...
throw new Exception("bad request yaddah...yaddah...yaddah...");
}
catch (Exception e)
{
return new ResponseEntity(e.getMessage, HttpStatus.BAD_REQUEST);
}
return null;
}
jQuery/AJAX
Your code is alright, just call jqXHR.responseText(). Also, the signature of the success function is (data, textStatus, jqXHR) (jqXHR comes third, not first).
ResponseEntity
ResponseEntity can be returned in multiple ways:
//Equivalent
return new ResponseEntity(someString, HttpStatus.OK);
return ResponseEntity.ok(someString);
return ResponseEntity.ok().body(someString);
ResponseEntity uses generics, like ResponseEntity<T>. So, if your method returns List you can use private ReponseEntity<List<MyDTO>>.
Hopefully this still helps you.
Your jQuery POST request is a success as long as you can return the value from the server side.
You don't get an error in your jquery (necessarily) even if you get it on the server.
You should distinguish between errors and successes in your server side response to the client. Jquery will execute the "success" callback either way!

Categories