Spring REST Exception - getting the response payload - rest

I have the following:
The "400 Bad request" is converted to a ResourceAccessException in Spring.
Is there any way to retrieve the payload here? I want to send the "errorMessage" further up the call chain.
Code-wise the following is used to do the request:
public <T> T post(String url, Object request, Class<T> className) {
try {
return logEnhancedRestTemplate.postForObject(url, request, className);
} catch(RestClientException ex) {
throw handleErrors(ex, url);
}
}
It is in the "handleErrors" method I want to use the "errorMessage" from the body.

If you want to retrieve the message of an exception use the method getMessage().
In your specific example maybe is better if you catch a generic exception, since I suppose that every type of Runtime exception should call your method handleErrors(ex, url).
If this is the case, I suggest you to modify your code with:
public <T> T post(String url, Object request, Class<T> className) {
try {
return logEnhancedRestTemplate.postForObject(url, request, className);
} catch(Exception ex) {
throw handleErrors(ex, url);
}
}

Related

How to throw an exception in on error part of reactive Spring WebClient call?

I would like the following method to throw a custom exception if an error occurs:
#Service
public class MyClass {
private final WebClient webClient;
public MatcherClient(#Value("${my.url}") final String myUrl) {
this.webClient = WebClient.create(myUrl);
}
public void sendAsync(String request) {
Mono<MyCustomResponse> result = webClient.post()
.header(HttpHeaders.CONTENT_TYPE, "application/json")
.body(BodyInserters.fromObject(request))
.retrieve()
.doOnError(throwable -> throw new CustomException(throwable.getMessage()))
.subscribe(response -> log.info(response));
}
}
I have also set up a unit test expecting the CustomException to be thrown. Unfortunately the test fails and the Exception is kind of wrapped into a Mono object. Here also the test code for reference:
#Test(expected = CustomException.class)
public void testSendAsyncRethrowingException() {
MockResponse mockResponse = new MockResponse()
.setHeader(HttpHeaders.CONTENT_TYPE, "application/json")
.setResponseCode(500).setBody("Server error");
mockWebServer.enqueue(mockResponse);
matcherService.matchAsync(track);
}
I'm using the MockWebServer to mock an error in the test.
So, how should I implement the doOnError or onError part if the call in order to make my method really to throw an exception?
I'd advise to expose a reactive API that returns the Mono<Void> from the webclient, especially if you name your method "sendAsync". It's not async if you have to block for the call to return/fail. If you want to provide a sendSync() alternative, you can always make it call sendAsync().block().
For the conversion of exception, you can use the dedicated onErrorMap operator.
For the test, the thing is, you can't 100% test asynchronous code with purely imperative and synchronous constructs (like JUnit's Test(expected=?) annotation). (although some reactive operator don't induce parallelism so this kind of test can sometimes work).
You can also use .block() here (testing is one of the rare occurrences where this is unlikely to be problematic).
But if I were you I'd get in the habit of using StepVerifier from reactor-test. To give an example that sums up my recommendations:
#Service
public class MyClass {
private final WebClient webClient;
public MatcherClient(#Value("${my.url}") final String myUrl) {
this.webClient = WebClient.create(myUrl);
}
public Mono<MyCustomResponse> sendAsync(String request) {
return webClient.post()
.header(HttpHeaders.CONTENT_TYPE, "application/json")
.body(BodyInserters.fromObject(request))
.retrieve()
.onErrorMap(throwable -> new CustomException(throwable.getMessage()))
//if you really need to hardcode that logging
//(can also be done by users who decide to subscribe or further add operators)
.doOnNext(response -> log.info(response));
}
}
and the test:
#Test(expected = CustomException.class)
public void testSendAsyncRethrowingException() {
MockResponse mockResponse = new MockResponse()
.setHeader(HttpHeaders.CONTENT_TYPE, "application/json")
.setResponseCode(500).setBody("Server error");
mockWebServer.enqueue(mockResponse);
//Monos are generally lazy, so the code below doesn't trigger any HTTP request yet
Mono<MyCustomResponse> underTest = matcherService.matchAsync(track);
StepVerifier.create(underTest)
.expectErrorSatisfies(t -> assertThat(t).isInstanceOf(CustomException.class)
.hasMessage(throwable.getMessage())
)
.verify(); //this triggers the Mono, compares the
//signals to the expectations/assertions and wait for mono's completion
}
The retrieve() method in WebClient throws a WebClientResponseException
whenever a response with status code 4xx or 5xx is received.
1. You can customize the exception using the onStatus() method
public Mono<JSONObject> listGithubRepositories() {
return webClient.get()
.uri(URL)
.retrieve()
.onStatus(HttpStatus::is4xxClientError, clientResponse ->
Mono.error(new MyCustomClientException())
)
.onStatus(HttpStatus::is5xxServerError, clientResponse ->
Mono.error(new MyCustomServerException())
)
.bodyToMono(JSONObject.class);
}
2. Throw the custom exception by checking the response status
Mono<Object> result = webClient.get().uri(URL).exchange().log().flatMap(entity -> {
HttpStatus statusCode = entity.statusCode();
if (statusCode.is4xxClientError() || statusCode.is5xxServerError())
{
return Mono.error(new Exception(statusCode.toString()));
}
return Mono.just(entity);
}).flatMap(clientResponse -> clientResponse.bodyToMono(JSONObject.class))
Reference: https://www.callicoder.com/spring-5-reactive-webclient-webtestclient-examples/
Instead of using doOnError I swiched to subscribe method accepting also an error consumer:
Mono<MyCustomResponse> result = webClient.post()
.header(HttpHeaders.CONTENT_TYPE, "application/json")
.body(BodyInserters.fromObject(request))
.retrieve()
.subscribe(response -> log.info(response),
throwable -> throw new CustomException(throwable.getMessage()));
This documentation helps a lot: https://projectreactor.io/docs/core/release/reference/index.html#_error_handling_operators

Is it possible to apply dictionaries for Citrus static response adapter response template?

I'm using Citrus static response adapter to mock services, and I need to change values in its payload for every test case. Ideally I think about usage of dictionaries for each test case. There is sample of my current scenario:
#Autowired
#Qualifier("checkRegistrationEndpointAdapter")
public StaticResponseEndpointAdapter checkRegistrationEndpointAdapter;
protected void setAdapterResponse(StaticResponseEndpointAdapter adapter, String filenamepath){
URL url = this.getClass().getResource(filenamepath);
String payload = null;
try {
payload = Resources.toString(url, Charsets.UTF_8);
} catch (IOException e) {
e.printStackTrace();
}
adapter.setMessagePayload(payload);
}
#CitrusTest
public void TestCase02() throws IOException {
http()
.client(CLIENT)
.post()
.payload(new ClassPathResource("templates/thisStartRequestMsg.xml", getClass()))
.dictionary("TC02");
http()
.client(CLIENT)
.response()
.messageType("xml")
.payload(new ClassPathResource("templates/thisStartResponseMsg.xml", getClass()));
action(new AbstractTestAction() {
#Override
public void doExecute(TestContext testContext) {
setAdapterResponse(checkRegistrationEndpointAdapter, "templates/check-registration-v1CheckRegistrationResponseMsg.xml");
}
});
http()
.client(CLIENT)
.response()
.messageType("xml")
.payload(new ClassPathResource("templates/check-registration-v1CheckRegistrationRequestMsg.xml", getClass()))
.dictionary("TC02");
}
How can I apply dictionary to the payload set in my setAdapterResponse method?
Note: this question relates to Can I use Citrus variable in Citrus static response adapter payload?
Static response adapter has currently no support for data dictionaries. I wonder why you put so much effort into static response adapters? Why not using the full Citrus http server power with receiving the request and providing a response inside the test case?

How to map exception for gwt-resty

I am currently using gwt-resty and jersey for the server side. The problem I have run into is how do I map an exception for the MethodCallback implementation. I have created an ExceptionMapper which converts the exception to json and returns it in json format but the onFailure method is giving me the generic error message for my exception, "Failed BAD Request"
The question is how do I convert the exception into something that gwt-resty can process the exception in order to get the message from the server side exception.
Here is my service implementation
service.getCurrentAddress("123456", new MethodCallback<Address>() {
#Override
public void onSuccess(Method method, Address response) {
Window.alert("Got your address" + response);
}
#Override
public void onFailure(Method method, Throwable e) {
GWT.log("failed", e);
GWT.log("Failed " + e.getMessage());
}
});
}
Here is my exception mapper.
#Provider
public class VendorExceptionMapper implements ExceptionMapper<Exception> {
#Override
public Response toResponse(Exception exception) {
return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON).entity(exception).build();
}
}
I am not sure I understood your question but I think that you can parse Throwable e to get your exception in case of failure.
You can also intercept your exception by coding a restyGWT dispatcher and treat it before entering the onFailure().

GWT RequestBuilder Post Response return 0 StatusCode

I have created a very simple servlet that uses HTTP Post method. I have tested it on my local Apache Tomcat server using a simple HTML form that works. I want to integrate it with my GWT app. I am able to call it using FormPanel - in that case it downloads content and there is a flicker in my browser window.
I know I need to use RequestBuilder to access it. But my response.getStatusCode() in my overloaded public void onResponseReceived(Request request, Response response) method always return status as 0 and response.getText() return null
String url = "http://localhost:8080/servlets/servlet/ShapeColor";
builder = new RequestBuilder(RequestBuilder.POST, URL.encode(url));
try {
String json = getJSONString();
//builder.setTimeoutMillis(10000);
builder.setHeader("Access-Control-Allow-Origin", "*");
builder.setHeader("Content-type", "application/x-www-form-urlencoded");
builder.sendRequest(json, new RequestCallback() {
#Override
public void onError(Request request, Throwable exception) {
Window.alert("Couldn't retrieve JSON");
}
#Override
public void onResponseReceived(Request request, Response response) {
if (200 == response.getStatusCode()) {
System.out.println("res:"+response.getText());
} else {
System.out.println("err: " + response.getStatusCode()+","+response.getText());
}
}
});
//Request response = builder.send();
} catch (RequestException e) {
// TODO Auto-generated catch block
}
I have tried many thing including changing my servlet following CORS reference ( https://code.google.com/p/gwtquery/wiki/Ajax#CORS_%28Cross_Origin_Resource_Sharing%29 )
It always works on browser using my test.html, but not from my App. Although, onResponseReceived method always gets called
Thanks
KKM
Have you checked if your call in the app violates the Same-origin policy (http://en.wikipedia.org/wiki/Same-origin_policy) in some way? The GWT RequestBuilder uses XMLHttpRequest internally, so it does fall under the SOP.
Does your GWT app run inside the same domain (server + port) as the servlet? Does it use the same protocol (https or http)?

GWT - spring security - session timeout

I have a GWT + Spring Security web app. I was trying to add:
<security:session-management invalid-session-url="/X.html"/>
However, when I try to test this. It seems I see a:
com.google.gwt.user.client.rpc.InvocationException
with message as the HTML content of X.html. Can someone please advise on how to fix this?
Because GWT communicates with a server via Ajax RPC requests, the browser will not be redirected to X.html. What you need to do in your service calls is throw an exception if they are not authorized and handle in in void onFailure(Throwable caught) method of your AsyncCallback.
If you want to redirect to /X.html try:
Window.Location.replace(GWT.getHostPageBaseURL()+"X.html");
However, if you want to send the request to the server use RequestBuilder:
String url = GWT.getHostPageBaseURL() + "/X.html";
RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, URL.encode(url));
try {
Request request = builder.sendRequest(null, new RequestCallback() {
public void onError(Request request, Throwable exception) {
// invalid request
}
public void onResponseReceived(Request request, Response response) {
if (200 == response.getStatusCode()) {
// success
} else {
// sth went wrong
}
}
});
} catch (RequestException e) {
// couldn't connect to server
}