WireMock gives a null response body when mocking an API call using spring boot resttemplate - spring-boot

I'm facing a weird issue with Wiremock. The code below returns a null response body. Any insight will be very much appreciated.
Stub in my test:
WireMock.stubFor(post(urlPathEqualTo("http://localhost:8080/mapper"))
.willReturn(WireMock.aResponse()
.withStatus(HttpStatus.OK.value())
.withBody(asJson("ct/slotting-response/create_sample_response1.json"))
.withHeader("Content-Type","application/json;charset=UTF-8")));
Actual API call using spring boot resttemplate:
public ResponseEntity<SampleResponse> getsampleValue(final SampleRequest request, RequestHeader requestHeader) throws SlottingException {
try {
log.info("Sending request[payload={}]", request);
final HttpHeaders headers = getRequestHeader(requestHeader);
HttpEntity<?> entity = new HttpEntity<>(request, headers);
final ResponseEntity<SampleResponse> response =
restTemplate.postForEntity("http://localhost:8080/mapper",
entity, SampleResponse.class);
log.info("Sample response {}", response); // response.getBody() gives null
if (HttpStatus.OK.equals(response.getStatusCode())) {
log.info("Sample allocated successfully.");
}
else {
throw new SampleException("failed");
}
return response;
} catch (Exception e) {
throw new SampleException("Failed", e);
}
}
Can someone please point out any obvious mistakes you see in the Wiremock stub?

Related

Migrating from Jersey client to RestTemplate, but it catch 401 error as HttpClientErrorException but Jersey client was not throwing this error why?

In my Service there was Jersey client implementation to call a rest API now I was migrating this code to RestTemplate.
In old code when there was a 401 error that comes as a response from the backend and I store the response in an object.
But when I migrated the code to RestTeplate the 401 is caught by HttpClientErrorException class so I am not able to get the response since the code flow goes to the catch block.
Jersey Client code
public Employees getEmployees1() throws MyException {
Employee employee=new Employee(23, "Test", "Test", "Test#test.com");
ClientResponse response=null;
try {
Client client = Client.create();
WebResource webResource = client.resource("http://localhost:8080/employees/");
response = webResource.accept("application/json")
.type("application/json").header("Authorization", "invalid Data").post(ClientResponse.class, employee);
}catch (RuntimeException e) {
logger.error("Runtime Error Occured -{} Response - {} ",e.getMessage(),response.getStatus());
throw new MyException("Unexpected Error Occured",e);
}catch (Exception e) {
logger.error("Some Error Occured -{} Response - {} ",e.getMessage(),response.getStatus());
throw new MyException("Unexpected Error Occured",e);
}
return response.readEntity(Employees.class);
}
RestTemplate Code
public Employees getEmployees() throws MyException {
Employee employee=new Employee(23, "Test", "Test", "Test#test.com");
HttpHeaders headers=new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
headers.add(HttpHeaders.AUTHORIZATION, "invalid Data");
ResponseEntity<Employees> response=null;
try {
response = this.restTemplate.exchange("http://localhost:8080/employees/", HttpMethod.POST, new HttpEntity<Employee>(employee,headers), Employees.class);
}catch (RuntimeException e) {
logger.error("Runtime Error Occured -{} Response - {} ",e.getMessage(),response.getStatusCode());
throw new MyException("Unexpected Error Occured",e);
}catch (Exception e) {
logger.error("Some Error Occured -{} Response - {} ",e.getMessage(),response.getStatusCode());
throw new MyException("Unexpected Error Occured",e);
}
return response.getBody();
}
By default RestTemplate throws an HttpStatusCodeException (a child of it) for all 400+ status codes - see DefaultResponseErrorHandler. You can change this behavior by setting your own implementation of ResponseErrorHandler to RestTemplate using setErrorHandler or if RestTemplate is constructed using RestTemplateBuilder - using errorHandler method of the builder.
I used the default ResponseErrorHandler, by using this it will bypass all the ResponseError exception
RestTemplate rt = restTemplateBuilder.errorHandler(new ResponseErrorHandler(){
#Override
public boolean hasError(ClientHttpResponse response) throws IOException {
return false;
}
#Override
public void handleError(ClientHttpResponse response) throws IOException {
}})
.build();

Pact consumer test does not successfully mock the spring webclient request using the created pact

I am new to Pact Contract testing and I am trying to create a Pact consumer test to validate a method that calls an api with get request. The api request is made using Spring Webclient.
I am not able to create the webclient object by just providing the Pact mockserver eg.
WebClient webClient = WebClient.builder().baseUrl(mockServer.getUrl()).build();
I am getting the exception java.lang.IllegalStateException: No suitable default ClientHttpConnector found. The explanation I get on the internet for that , is to include reactor-netty-http and I was able to get past this issue when i included that in the POM. But I don't think that is the right solution here because I need the mockserver to respond to the webclient request and it is not. Has anyone dealt with this issue before or am I doing this wrong?
Here is the code snippet:
public RequestResponsePact pactMethod(PactDslWithProvider builder) {
Map<String, String> headers = new HashMap<>();
headers.put(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
return builder.given("Consumer request")
.uponReceiving(" getResource call")
.path("/path")
.method("GET")
.willRespondWith()
.status(200)
.headers(headers)
.body(RESPONSE_JSON).toPact();
}
#Test
#PactTestFor(pactMethod = "pactMethod", port = "9999")
public void consumerTest(MockServer mockServer) {
WebClient webClient = WebClient.builder().baseUrl(mockServer.getUrl()).build();
ConsumerServiceClient consumerServiceClient = new ConsumerServiceClient(webClient);
Mono<Data> data = consumerServiceClient.getData();
StepVerifier.create(data)
.assertNext(resp -> {
try {
Value value = resp.getValue();
Assertions.assertFalse( value.isEmpty());
} catch (Exception e) {
log.error("Unable to convert response to Value", e);
Assertions.fail();
}
}).expectComplete()
.verify();
}
The webclient call:
webClient.get()
.uri("/path")
.retrieve()
.onStatus(status -> status == HttpStatus.NOT_FOUND,
res -> Mono.error(new RunTimeException()))
.bodyToMono(clazz);

How to handle the http response from an api call efficiently using spring boot

When we fire an api call to a 3rd party service, we can get different HTTP responses (200, 404 etc.). How can we handle them in a standard way?
private ResponseEntity<ResultHolder> responseEntity;
public ResponseEntity<ResultHolder> serviceTest(String searchText, String countryCode) {
logger.info("Service started");
String url = prepareUrl(searchText,countryCode); //custom method
HttpHeaders header = new HttpHeaders();
prepareHeader(header); //custom method
HttpEntity<String> requestEntity = new HttpEntity<String>(header);
try {
logger.info("Calling the API");
responseEntity = restClient.exchange(url,
HttpMethod.GET,
requestEntity,
ResultHolder.class);
}catch (Exception e) {
logger.error("Exception while calling the API "+ e);
//Here I am trying to get the value of response code and handle based on that
//Is this the right way to solve the problem?
if(responseEntity.getStatusCodeValue() != 200) {
responseEntity = new ResponseEntity<ResultHolder>(
HttpStatus.BAD_REQUEST);
}
}
logger.info("Service Ended");
return responseEntity;
}
What if I want to display distinct custom messages for server side errors and for user errors like 'No Internet Connection'.
Kindly help me to understand the good practises in this area.
Thank you

Handle HttpClientErrorException$BadRequest: 400 Bad Request in Cucumber RestTemplate

Hi I have written a Cucumber test case where i send a POST request with an XML body, output of that request is 400 Error with an XML body, which is expected and when i throw the request i get that too, but what i get is below:
org.springframework.web.client.HttpClientErrorException$BadRequest: 400 Bad Request
at org.springframework.web.client.HttpClientErrorException.create(HttpClientErrorException.java:79)
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:97)
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:79)
at org.springframework.web.client.ResponseErrorHandler.handleError(ResponseErrorHandler.java:63)
at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:777)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:735)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:709)
at org.springframework.web.client.RestTemplate.postForEntity(RestTemplate.java:462)
at uk.co.argos.services.order.StepDefinations.TestMethods.POSTrestTemplatewithXML(TestMethods.java:147)
at uk.co.argos.services.order.StepDefinations.StepDefs.user_hits_the_getSlot_request_with_OrderEnricher_with_and_and(StepDefs.java:118)
at ✽.Given User hits the getSlot request with OrderEnricher with "2020-40-32" and "150" and "MK92NW"(OrderEnricher_Negative.feature:5)
And my test step failes with bad request, But ideally that is my expected and i want to pass my test step & scenario, not sure how should i handle it, i have tried applying multiple things. Can anyone help please?
public static ResponseEntity<String> POSTrestTemplatewithXML(URI uri, String XMLforPOST){
ResponseEntity<String> responseEntity = null;
try {
RestTemplate restTemplate=new RestTemplate();
List<HttpMessageConverter<?>> messageConverters=new ArrayList<HttpMessageConverter<?>>();
messageConverters.add(new StringHttpMessageConverter());
restTemplate.setMessageConverters(messageConverters);
HttpHeaders headers=new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_XML);
HttpEntity<String> request=new HttpEntity<String>(XMLforPOST, headers);
responseEntity=restTemplate.postForEntity(uri, request, String.class);
}
catch (Exception e){
System.out.println("RESPONSE-" +responseEntity);
byte[] bytes = ((HttpClientErrorException.BadRequest)e).getResponseBodyAsByteArray();
assertTrue(true);
//Convert byte[] to String
String s = new String(bytes);
System.out.println(s);
e.printStackTrace();
}
return responseEntity;
}
Please update your catch method like following :
try{
//your code
} catch (HttpClientErrorException e){
//your code
}

java.lang.IllegalArgumentException: Comparison method violates its general contract! in Spring Rest Template

I am facing a weird issue while calling a REST url using Spring's RestTemplate.I am using Spring Boot.
The error is occurring only after approx 10 to 15 successful calls and thereafter erratically. I can smoothly exchange data before the error, in the first 1 to 15 calls approx. Url is like someresturl/param1/param2/param3.
public ResponseEntity<String> callRestUrl(CustomReqClass req) {
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
restTemplate.getMessageConverters().add(new StringHttpMessageConverter());
StringBuilder url = new StringBuilder("someresturl");
finishTaskUrl.append("/").append(param1).append("/").append(param2).append("/").append(param3);
ResponseEntity<String> response = null;
HttpEntity<CustomReqClass> request = new HttpEntity<CustomReqClass>(req, getHTTPHeaders());
try {
//first approach
response = restTemplate.postForEntity(url.toString(), request, String.class, Collections.<String, String>emptyMap());
//second approach
response = restTemplate.exchange(url.toString(), HttpMethod.POST, request, String.class);
} catch (Exception e) {
LOGGER.info("Error calling url" + e);
}
return response;
}
public MultiValueMap<String, String> getHTTPHeaders() {
MultiValueMap<String, String> headers = new LinkedMultiValueMap<String, String>();
headers.add("Authorization", "Basic authabcdxyz");
headers.add("Content-Type", "application/json");
return headers;
}
Here I am autowiring restTemplate object in the class where I am using this.
I have tried both the above methods postForEntity and exchange of Rest template. Error is occurring for both.
The exception I am getting after first few successful attempts:
java.lang.IllegalArgumentException: Comparison method violates its general contract!
As an additional thought, the above piece of code is being scheduled by Spring Scheduler mechanism. Is it possible internal threading used in scheduler is causing this issue?

Resources