False positive in consumer tests for valid and invalid reques(matching multiple contracts) - spring-cloud-contract

We have the case where we have two different outcomes on the producer side depending on a request one is for success and on which trows error message.
A simplified sample with two contracts:
1)Contract.make {
request {
method PUT()
urlPath("/sample")
headers {
contentType('application/json')
}
body("{\"acc\": \"1234A\" ,\"case\":\"abc23\",\"re\":2018/12/12}")
}
response {
status BAD_REQUEST()
}
}
2)
Contract.make {
request {
method PUT()
urlPath("/sample")
headers {
contentType('application/json')
}
body("{\"acc\": \"1234\" ,\"case\":\"abc23\",\"re\":2018/12/12}")
}
response {
status 200
}
}
On the consumer side it is able to match both request where as , when i run the invalid request test case it is throwing org.springframework.web.client.HttpClientErrorException$BadRequest: 400 Bad Request
But the for both scenarios i can able to see request and coresponding response, i can able to see in the logs
Can any body help me in this?
Thanks
These are my consumer test cases
1) its sucess request scenauro its working fine it is getting 200
enter code here
#Test
public void should_update_case_sucess() throws Exception {
RestTemplate restTemplate = new RestTemplate();
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add("Content-Type", "application/json");
ResponseEntity<String> response = restTemplate.exchange(
"http://localhost:8083//sample",
HttpMethod.PUT,
new HttpEntity<>("{\"acc\":\"1234\",\"case\":\"abc23\",\"re\":\"20181212\"}", httpHeaders), String.class);
BDDAssertions.then(response.getStatusCodeValue()).isEqualTo(200);
}
2)
This is the failure scenario which not getting 400 respose instead it is trowing httpclient error,it is not able to invoke target
enter code here
#Test
public void should_update_case_error() throws Exception {
RestTemplate restTemplate = new RestTemplate();
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add("Content-Type", "application/json");
ResponseEntity<String> response = restTemplate.exchange(
"http://localhost:8083//sample",
HttpMethod.PUT,
new HttpEntity<>("{\"acc\":\"1234A\",\"caseNumber\":\"abc23\",\"representmentStartDate\":\"20181212\"}", httpHeaders), String.class);
BDDAssertions.then(response.getStatusCodeValue()).isEqualTo(400);
}
Could you help me in this

This will not work cause wiremock has two same requests and two different responses so the first one wins.
What you have to do is to alert the request a little bit to differentiate between the two and that way you'll find the proper response.

Related

Consume Html response using restTemplate

I want to consume html response using restTemplate and rerun that response to my html so i can add those content to my html page but getting below error tried so many alternatives but not luck
I want to consume every type of response and return that as it is to my html/jsp via ajax and render that content in a div.
HTML (ajax call) --- Spring MVC (rest call to 3rd party) --- application returns html
Code
#RequestMapping(value = "/xyz-service/**", method = {RequestMethod.GET, RequestMethod.PUT},produces="application/json;charset=UTF-8")
public Object mirrorRest(HttpServletRequest request) {
String url = request.getRequestURI();
return restTemplate.getForObject("http://xyz-service:8080"+url , String.class);
}
I am able to invoke my serive method that retuning html as respose but getting error
"Could not extract response: no suitable HttpMessageConverter found for response type [class java.lang.String] and content type [text/html;charset=UTF-8]"
]
The exception seem to have occurred because your request was missing the header parameters.
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", "Bearer " + apikey);
headers.set("Charset", "utf-8");
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<Request> entity = new HttpEntity<Request>(
req, headers); //incase if your request have a request body
try {
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, entity, String.class); //if no request body you could simply use headers parameter directly
logger.info(response.toString());
return response.getBody().toString();
} catch (HttpStatusCodeException exception) {
logger.info("API failed"+exception);
return null;
}
No you can't. An HTML page is not a json object: REST template is designed to consume RestServices.
You should use a URLConnection from jdk

Triggering a fallback using #HystrixProperty timeout for HTTP status codes and other exceptions

I have a function in my #Service class that is marked with #HystrixCommand.
This method acts as a client which sends a request to another service URL and gets back a response.
What I want to do is to trigger a fallback function when the response status code is anything other than 200. It will also trigger a fallback for any other exceptions (RuntimeExceptions etc.).
I want to do this by making use of the #HystrixProperty or #HystrixCommandProperty.
I want the client to ping the URL and listen for a 200 response status and if it does not get back a 200 status within a certain time-frame I want it to fallback.
If it gets back a 200 status normally within a certain time it should not trigger the fallback.
#HystrixCommand(fallbackMethod="fallbackPerformOperation")
public Future<Object> performOperation(String requestString) throws InterruptedException
return new AsyncResult<Object>() {
#Override
public Object invoke() {
Client client = null;
WebResource webResource = null;
ClientResponse response =null;
String results = null;
try{
client = Client.create();
webResource = client.resource(URL);
client.setConnectTimeout(10000);
client.setReadTimeout(10000);
response = webResource.type("application/xml")
.post(ClientResponse.class, requestString);
} finally {
client.destroy();
webResource = null;
}
return results;
}
};
}
I specifically want to make use of the #HystrixProperty or #HystrixCommandProperty so performing a check inside the method for response status code not being 200 and then throwing an Exception is not acceptable.
Instead of using Annotations will creating my own Command by extending the HystrixCommand Interface work?
Any ideas or resources for where I can start with this are more than welcome.
I don’t understand why you don’t want to check the response http status code and throw an exception if it is not 200? Doing that will give you the behaviour you desire. i.e. it will trigger a fall back for exceptions or non 200 responses.
You can set the timeout in the client, however I would opt for using the hystrix timeout values. That way you can use Archaius to dynamically change the value at runtime if desired.
You can use the Hystrix command annotation or extend the HystrixCommand class. Both options will provide you with your desired behaviour
Here is an example using the annotation.
#HystrixCommand(fallbackMethod = "getRequestFallback")
public String performGetRequest(String uri) {
Client client = Client.create();
WebResource webResource = client.resource(uri);
ClientResponse response = webResource.get(ClientResponse.class);
if (response.getStatus() != 200) {
throw new RuntimeException("Invalid response status");
}
return response.getEntity(String.class);
}
public String getRequestFallback(String uri) {
return "Fallback Value";
}

Modify request/observable between retry

I have rxjava(observable) + retrofit2 together to make http requests to my application. I create OkHttpClient once for app and don't want to recreate it.
I have retry logic implemented on observable level - using filter, retryWhen together.
What I want - if request finished with error from server side, i want to retry it and send additional header with it.
So, I dont understand neither how can I modify observable inside retryWhen nor how to get the knowledge about observable from interceptor level.
Any ideas and/or knowledge about possible approaches?
You need to create your own Interceptor implementation where you can setup the header logic. Something like
public class FallbackInterceptor implements Interceptor {
static String header1Key = "key1";
static String extraHeaderKey = "key2";
String header1, extraHeader;
boolean useextraheader = false;
public FallbackInterceptor(string header1, string extraheader) {
this.header1 = header1;
this.extraheader = extraheader;
}
public void setUseExtraHeader(boolean useextraheader) {
this.userextraheader = useextraheader;
}
#Override
public Response intercept(Interceptor.Chain chain) throws IOException {
Request original = chain.request();
// Add request headers
Request.Builder requestBuilder = original.newBuilder().header(header1Key, header1);
if (useExtraHeader) {
requestBuilder = requestBuilder.header(extraHeaderKey, extraHeader)
}
Request newRequest = requestBuilder.method(original.method(), original.body())
.build();
// Return the response
return chain.proceed(request);
}
}
Add this to an okhttpclient and have your retrofit instance use this this. You can then manipulate the extraheader flag in your retry logic.

Spring MV 3.2 Exception Response Mapping

Spring 3.2.15, MVC-based REST API here (not Spring Boot, sadly!). I am trying to implement an exception mapper/handler that meets the following criteria:
No matter what happens (success or error), the Spring app always returns a response entity of MyAppResponse (see below); and
In the event of processing a request successfully, return an HTTP status of 200 (typical); and
In the event of processing a request and an exception occurs, I need to control the mapping of the specific exception to a particular HTTP status code
Spring MVC framework errors (such as BlahException) must map to HTTP 422
Custom app exceptions, such as my FizzBuzzException have their own status mapping schemes:
FizzBuzzException -> HTTP 401
FooBarException -> HTTP 403
OmgException -> HTTP 404
All other exceptions, that is, non-Spring exceptions, and non-custom app exceptions (the 3 listed above), should produce an HTTP 500
Where the MyAppResponse object is:
// Groovy pseudo-code
#Canonical
class MyAppResponse {
String detail
String randomNumber
}
It appears like ResponseEntityExceptionHandler might be able to do this for me, but I'm not seeing the forest through the trees w.r.t. how it gets passed arguments. I'm hoping I can do something like:
// Groovy-pseudo code
#ControllerAdvice
class MyAppExceptionMapper extends ResponseEntityExceptionHandler {
ResponseEntity<Object> handleFizzBuzzException(FizzBuzzException fbEx, HttpHeaders headers, HttpStatus status) {
// TODO: How to reset status to 401?
status = ???
new ResponseEntity(fbEx.message, headers, status)
}
ResponseEntity<Object> handleFooBarException(FooBarException fbEx, HttpHeaders headers, HttpStatus status) {
// TODO: How to reset status to 403?
status = ???
new ResponseEntity(fbEx.message, headers, status)
}
ResponseEntity<Object> handleOmgException(OmgException omgEx, HttpHeaders headers, HttpStatus status) {
// TODO: How to reset status to 404?
status = ???
new ResponseEntity(omgEx.message, headers, status)
}
// Now map all Spring-generated exceptions to 422
ResponseEntity<Object> handleAllSpringExceptions(SpringException springEx, HttpHeaders headers, HttpStatus status) {
// TODO: How to reset status to 422?
status = ???
new ResponseEntity(springEx.message, headers, status)
}
// Everything else is a 500...
ResponseEntity<Object> handleAllOtherExceptions(Exception ex, HttpHeaders headers, HttpStatus status) {
// TODO: How to reset status to 500?
status = ???
new ResponseEntity("Whoops, something happened. Lol.", headers, status)
}
}
Any idea how I can fully implement this mapping logic and the requirement for the entity to be a MyAppResponse instance and not just a string?
Then, is annotating the class with #ControllerAdvice the only thing that I need to do to configure Spring to use it?
To reduce #bond-java-bond answer you do not need to build ResponseEntity by yourself:
Use #ResponseStatus for each handleSomeException method (e.g. #ResponseStatus(HttpStatus.UNAUTHORIZED))
Return custom MyAppResponse from those methods
But if each kind of exceptions will be processed by the same way (diffs by HTTP status only) I suggest to reduce MyAppExceptionMapper like this:
#ControllerAdvice
public class MyAppExceptionMapper {
private final Map<Class<?>, HttpStatus> map;
{
map = new HashMap<>();
map.put(FizzBuzzException.class, HttpStatus.UNAUTHORIZED);
map.put(FooBarException.class, HttpStatus.FORBIDDEN);
map.put(NoSuchRequestHandlingMethodException.class, HttpStatus.UNPROCESSABLE_ENTITY);
/* List Spring specific exceptions here as #bond-java-bond suggested */
map.put(Exception.class, HttpStatus.INTERNAL_SERVER_ERROR);
}
// Handle all exceptions
#ExceptionHandler(Exception.class)
#ResponseBody
public ResponseEntity<MyAppResponse> handleException(Exception exception) {
MyAppResponse response = new MyAppResponse();
// Fill response with details
HttpStatus status = map.get(exception.getClass());
if (status == null) {
status = map.get(Exception.class);// By default
}
return new ResponseEntity<>(response, status);
}
}
Pros:
Pretty short.
No code duplication.
Slightly more effective.
Easy to extend.
Also, you can move mapping configuration outside and inject it.
How to configure MVC Dispatcher Servlet
First of all, check if mvc-dispatcher-servlet.xml (or another contextConfigLocation from web.xml) contains:
<context:component-scan base-package="base.package"/>
<mvc:annotation-driven/>
Secondly, check if #ControllerAdvice annotated class and #Controller annotated class both belong to subpackage of base.package.
See complete examples at Exception Handling in Spring MVC or Spring MVC #ExceptionHandler Example for more details.
First the error / exception handler should not worry about the success response.
Thus the responsibility of success response should lie with controller (plain or REST controller) method(s) annotated with #RequestMapping as below
#RequestMapping(value = "/demo", method = RequestMethod.GET)
#ResponseStatus(value = HttpStatus.OK)
public MyAppResponse doSomething() { .... }
For mapping a particular HTTP response code with exception(s) simply write a #ControllerAdvice as below (no additional configuration required)
#ControllerAdvice
public class CustomExceptionHandler {
// Handle FizzBuzzException with status code as 401
#ExceptionHandler(value = FizzBuzzException.class)
#ResponseBody
public ResponseEntity<MyAppResponse> handleException(FizzBuzzException ex) {
return new ResponseEntity<MyAppResponse>(buildResponse(ex), HttpStatus.UNAUTHORIZED);
}
// Handle FooBarException with status code as 403
#ExceptionHandler(value = FooBarException.class)
#ResponseBody
public ResponseEntity<MyAppResponse> handleException(FooBarException ex) {
return new ResponseEntity<MyAppResponse>(buildResponse(ex), HttpStatus.FORBIDDEN);
}
// Handle OmgException with status code as 404
#ExceptionHandler(value = OmgException.class)
#ResponseBody
public ResponseEntity<MyAppResponse> handleException(OmgException ex) {
return new ResponseEntity<MyAppResponse>(buildResponse(ex), HttpStatus.NOT_FOUND);
}
// handle Spring MVC specific exceptions with status code 422
#ExceptionHandler(value = {NoSuchRequestHandlingMethodException.class, HttpRequestMethodNotSupportedException.class, HttpMediaTypeNotSupportedException.class,
HttpMediaTypeNotAcceptableException.class, MissingPathVariableException.class, MissingServletRequestParameterException.class, ServletRequestBindingException.class,
ConversionNotSupportedException.class, TypeMismatchException.class, HttpMessageNotReadableException.class, HttpMessageNotWritableException.class, MethodArgumentNotValidException.class,
MissingServletRequestPartException.class, BindException.class, NoHandlerFoundException.class, AsyncRequestTimeoutException.class})
#ResponseBody
public ResponseEntity<MyAppResponse> handleException(Exception ex) {
return new ResponseEntity<MyAppResponse>(buildResponse(ex), HttpStatus.UNPROCESSABLE_ENTITY);
}
// Handle rest of the exception(s) with status code as 500
#ExceptionHandler(value = Exception.class)
#ResponseBody
public ResponseEntity<MyAppResponse> handleException(Exception ex) {
return new ResponseEntity<MyAppResponse>(buildResponse(ex), HttpStatus.INTERNAL_SERVER_ERROR);
}
private MyAppResponse buildResponse(Throwable t) {
MyAppResponse response = new MyAppResponse();
// supply value to response object
return response;
}
}
Let know in comments if any further information is required.
P.S.: List of Spring MVC exception reference

How should I implement the HEAD response for a dynamically generated resource?

Below code is written with Spring MVC. I simulate the dynamic response generation by reading a file first and send it to client.
For a GET method, the response will contain the Transfer-Encoding: chunked header rather than the Content-Length header.
For a HEAD method, how should I implement the response? Should I manually insert the Transfer-Encoding: chunked header and remove the Content-Length header?
#RestController
public class ChunkedTransferAPI {
#Autowired
ServletContext servletContext;
#RequestMapping(value = "xxx.iso", method = { RequestMethod.GET })
public void doChunkedGET(HttpServletResponse response) {
String filename = "/xxx.iso";
try {
ServletOutputStream output = response.getOutputStream();
InputStream input = servletContext.getResourceAsStream(filename);
BufferedInputStream bufferedInput = new BufferedInputStream(input);
int datum = bufferedInput.read();
while (datum != -1) {
output.write(datum); //data transfer happens here.
datum = bufferedInput.read();
}
output.flush();
output.close();
} catch (IOException e) {
// TODO Auto-generated catch block
System.out.println(e.getMessage());
}
}
#RequestMapping(value = "xxx.iso", method = { RequestMethod.HEAD })
public void doChunkedHEAD(HttpServletResponse response) {
// response.setHeader("Server", "Apache-Coyote/1.1");
// response.setHeader("Transfer-Encoding", "chunked");
}
}
My client's behavior is:
Initiate a HEAD request first to get the anticipated response size. This size is used to allocate some buffer.
Then initiate a GET request to actually get the response content and put it in the buffer.
I kind of have the feeling that I am catering to the client's behavior rather than following some RFC standard. I am worried that even if I can make the client happy with my response, it will fail with other servers' responses.
Anyone could shed some light on this? How should I implement the HEAD response?
Or maybe the client should NEVER rely on the HEAD response to decide the size of a GET response because the RFC says:
The server SHOULD send the same header fields in response to a HEAD
request as it would have sent if the request had been a GET, except
that the payload header fields (Section 3.3) MAY be omitted.
And Content-Length happens to be one of the payload header fields.

Resources