I'm using ResteasyClient to make a REST client to my another service A. Say, service A throws an exception CustomException with a message : Got Invalid request.
Here is how I am using the Client:
public Response callServiceA(final String query) {
ResteasyClient client = new ResteasyClientBuilder().build();
String link = "abc.com/serviceA";
ResteasyWebTarget target = client.target(link).path("call");
Form form = new Form();
form.param("query", query);
Response response;
try {
String data =
target.request(MediaType.APPLICATION_JSON_TYPE)
.post(Entity.entity(form,
MediaType.APPLICATION_FORM_URLENCODED_TYPE),
String.class);
response = Response.ok().entity(data).build();
} catch (Exception e) {
String message = e.getMessage();
e.printStackTrace();
response = Response.serverError().entity(e.getMessage()).build();
} finally{
client.close();
}
return response;
}
However, when I print the stacktrace, I'm unable to find my custom error message. I can just see the message as HTTP 400 Bad Request.
Could you please suggest me how to access the error message?
NOTE: I am able to get the error message when I call the serviceA using the restClient. Hence, I dont think there is an issue with the service.
Don't deserialize the response straight to a String.
String data = ...
.post(Entity.entity(form,
MediaType.APPLICATION_FORM_URLENCODED_TYPE),
String.class);
When you do this (and there is a problem), you just get a client side exception, which doesn't carry information about the response. Instead just get the Response with the overloaded post method
Response response = ...
.post(Entity.entity(form,
MediaType.APPLICATION_FORM_URLENCODED_TYPE));
Then you can get details from the Response, like the status and such. You can get the body with response.readEntity(String.class). This way you don't need to handle any exceptions. Just handle conditions based on the status.
Do note though that the Response above is an inbound Response, which is different from the outbound Response in your current code. So just make sure not to try and send out an inbound Response.
Also see this answer and it's comments for some design ideas.
Related
I am using my retrofit client when calling external api's.
I get a response code and also response body as well when status code is 200.
For status code non 200 [ex 400] with error object in response, it does not get and map response body whereas the external API is sending the body in case of a non 200.
Response body in that case is null.
Here is my builder
Retrofit.Builder builder =
new Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(JacksonConverterFactory.create(objectMapper))
.client(httpClient);
Retrofit retrofit = builder.build();
When calling:
Call<ResponseDto> call =
service.listSearch(listRequestDto);
try {
Response<ResponseDto> response = call.execute();
}
When the call is 200, ResponseDto is received and mapped but when it is non 200, it is null.
As you are using try and catch block. You can get the error in catch block and then you can decide on what you need to do. In case of an error, you won't get a response, it will directly go to catch block.
So your code will look something like this
try {
Response<ResponseDto> response = call.execute();
} catch (err) {
// Do what you want to do in case of error.
}
Hope this helps!
I have a Feign client with a method returning the feign.Response class. When another service throws an exception, feign puts an exception message on response body and puts status, but my service does not throw an exception. Can I throw an exception based on what I received in response like when I use ResponseEntity.
Feign client
#FeignClient(name = "ms-filestorage")
#RequestMapping(value = "/files", produces = "application/json")
public interface FileStorageApi {
#GetMapping(value = "/{id}")
Response getFileById(#PathVariable String id);
}
Usage of client
#Override
public Response getFileFromStorage(String fileId) {
Response fileStorageResponse = fileStorageApi.getFileById(fileId);
// NOW I USE THIS WAY FOR CHECKING RESPONSE BUT IT DOESN'T LOOK GOOD
//if (fileStorageResponse.status() != HttpStatus.OK.value()) {
// throw new OsagoServiceException();
//}
return fileStorageResponse;
}
Usually, if a Feign client call receives an error response from the API it is calling, it throws a FeignException.
This can be caught in a try / catch block (or a Feign ErrorDecoder if you want to be more sophisticated, but that's another post).
However, this is not the case if you map the error response into a Feign.Response return type - see this Github issue.
Instead of returning Feign.Response from getFileFromStorage(), you should create a custom Java object to hold the response, and you will then have access to the FeignException which you can handle as you wish.
Note that if you don't need access to the data that is returned from the API you are calling, changing the return type to void will also resolve this issue.
I am able to call soap service and getting the response from soap client does means connectivity is okay. But the request data values are not mapping to external system request. and we both are using same package and class names.
Please find the code as below:
UserListResponse response = null;
#PayloadRoot(namespace = NAMESPACE_URI, localPart = "UserList")
#ResponsePayload
public UserListResponse UserListRequest(#RequestPayload UserListRequest request) throws Exception {
System.out.println("Enters into UserList()");
try {
//Client call
UserServicesLocator locator = new UserServicesLocator();
UserServicesSoapStub stub = (UserServicesSoapStub) locator.getUserServicesSoap();
response = stub.userList(request);//here the request data values not mapping at external system side
} catch(Exception e) {
e.printStackTrace();
}
return response;
}
Note: Client classes are able to generated using wsdl and in that client classes having pojo structure with serialization and de-sterilization methods.
Can anyone please suggest on this issue.
I'm trying to a client (Android) talk to our server which is using sparkjava, but running into the issue that when the client is trying to parse the body of the response response.data with Volley, it's getting that the response body is empty. The client is sending a JsonRequestObject , which will throw a JSONException if the response's body is empty.
Here is our sparkJava controller:
public static String doThis(Request request, Response response) {
response.type("application/json");
// If the request fails validations, then return a 400
if (request.failsValidations()) {
response.status(HTTP_BAD_REQUEST); // 400
response.header("Error", "Bad request");
} else {
response.status(HTTP_SUCCESS); // 200
// Put the response into the data
String responseData = "{//someJson}"
response.header("data", responseData);
response.body(data);
}
return "";
}
I'm setting the same data in the header and body, but when I look at the response received on the client, the data is only in the header and not in the body. So I was thinking that Spark's response.body() method isn't really putting the data into the response being sent back.
Is the way response.body is represented in sparkjava different from how volley views it? Or is there another way to put data into the response body from spark?
You can do it in two ways:
Using a JSON Object
public static Object doThis(Request request, Response response) {
response.type("application/json");
JSONObject jo = new JSONObject();
jo.put("data", "someData");
return jo;
}
Using a string formatted as JSON
public static Object doThis(Request request, Response response) {
response.type("application/json");
return "{\"data\":\"someData\"}";
}
The first one is better IMO because you can modify the JSON object in a much more convenient way (but you have to import org.json.JSONObject).
Then, on the client side, you should treat the data as JSON data type. Hope it helps.
I have a webservice defined with Jersey in the server side like this:
#POST
#Consumes(MediaType.APPLICATION_XML)
#Path("/foo")
public Response bar(List<Foo> listFoo) {
try {
//save the resource
} catch (Exception e) {
log.error("Error saving", e);
return Response.status(Status.INTERNAL_SERVER_ERROR).build();
}
return Response.status(Status.OK).build();
}
I am trying to get the server status in my Jersey client like this:
Response response = ws.type(MediaType.APPLICATION_XML).post(Response.class,list);
But I get the error:
A message body reader for Java class javax.ws.rs.core.Response, and Java type class javax.ws.rs.core.Response, and MIME media type application/xml was not found javax.ws.rs.core.Response
I don't really need the Response object, just the status code, how could I get it?
Ok, I solved it by changing the request response type:
Response response = ws.type(MediaType.APPLICATION_XML).post(Response.class,list);
with
ClientResponse response = ws.type(MediaType.APPLICATION_XML).post(ClientResponse.class,list);
being ClientResponse a com.sun.jersey.api.client.ClientResponse
Add #Consumes annotation to your web-serivce and the parameter to your bar() method, because you are trying to put there some object named list.
And I would recommend you to use #POST instead, because canonical #PUT does not return a response.
UPD. By the way, you have your entity empty - you should better remove your #Produces annotation and just return Response with its status set.
UPD2. and remove .accept(MediaType.APPLICATION_XML) method from client side.