I am trying to write a test for patch end point using rest assured mock mvc.
But i am not able to create an object of jsonmerge patch to place in the body of the mock.below is the end point for which i need to wrote the test
#PatchMapping(path = "/{orderId}", consumes = "application/merge-patch+json")
public OrderDTO updateOrder(#PathVariable Long orderId, #RequestBody
JsonMergePatchImpl patchRequest){
return facade.patchOrder(orderId,patchRequest);
}
and following is what i'm trying but not able to figure out
Mockito.when(facade.patchOrder(any(),any())).thenReturn(orderDTO);
OrderDTO actual=given()
.contentType(MediaType.APPLICATION_JSON_VALUE)
.body()
.accept("application/merge-patch+json")
.when()
.patch(BASE_URL+"/"+1l)
.then()
.assertThat()
.statusCode(200).extract().as(OrderDTO.class);
My problem is i am not able to create an object for jsonmerge patch , and what to put in as content type
You can specify contentType as String:
.contentType("application/merge-patch+json")
Related
I am currently testing one of my services with Spring boot test.The service exports all user data and produces a CSV or PDF after successful completion. A file is downloade in browser.
Below is the code i have wrote in my test class
MvcResult result = MockMvc.perform(post("/api/user-accounts/export").param("query","id=='123'")
.contentType(MediaType.APPLICATION_JSON_VALUE)
.accept(MediaType.APPLICATION_PDF_VALUE)
.content(TestUtil.convertObjectToJsonBytes(userObjectDTO)))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_PDF_VALUE))
.andReturn();
String content = result.getResponse().getContentAsString(); // verify the response string.
Below is my resource class code (call comes to this place)-
#PostMapping("/user-accounts/export")
#Timed
public ResponseEntity<byte[]> exportAllUsers(#RequestParam Optional<String> query, #ApiParam Pageable pageable,
#RequestBody UserObjectDTO userObjectDTO) {
HttpHeaders headers = new HttpHeaders();
.
.
.
return new ResponseEntity<>(outputContents, headers, HttpStatus.OK);
}
While I debug my service, and place debug just before the exit, I get content Type as 'application/pdf' and status as 200.I have tried to replicate the same content type in my test case. Somehow it always throws below error during execution -
java.lang.AssertionError: Status
Expected :200
Actual :406
I would like to know, how should i inspect my response (ResponseEntity). Also what should be the desired content-type for response.
You have problem some where else. It appears that an exception/error occurred as noted by application/problem+json content type. This is probably set in the exception handler. As your client is only expecting application/pdf 406 is returned.
You can add a test case to read the error details to know what exactly the error is.
Something like
MvcResult result = MockMvc.perform(post("/api/user-accounts/export").param("query","id=='123'")
.contentType(MediaType.APPLICATION_JSON_VALUE)
.accept(MediaType.APPLICATION_PROBLEM_JSON_VALUE)
.content(TestUtil.convertObjectToJsonBytes(userObjectDTO)))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_PROBLEM_JSON_VALUE))
.andReturn();
String content = result.getResponse().getContentAsString(); // This should show you what the error is and you can adjust your code accordingly.
Going forward if you are expecting the error you can change the accept type to include both pdf and problem json type.
Note - This behaviors is dependent on the spring web mvc version you have.
The latest spring mvc version takes into account the content type header set in the response entity and ignores what is provided in the accept header and parses the response to format possible. So the same test you have will not return 406 code instead would return the content with application json problem content type.
I found the answer with help of #veeram and came to understand that my configuration for MappingJackson2HttpMessageConverter were lacking as per my requirement. I override its default supported Mediatype and it resolved the issue.
Default Supported -
implication/json
application*/json
Code change done to fix this case -
#Autowired
private MappingJackson2HttpMessageConverter jacksonMessageConverter;
List<MediaType> mediaTypes = new ArrayList<>();
mediaTypes.add(MediaType.ALL);
jacksonMessageConverter.setSupportedMediaTypes(mediaTypes);
406 means your client is asking for a contentType (probably pdf) that the server doesn't think it can provide.
I'm guessing the reason your code is working when you debug is that your rest client is not adding the ACCEPT header that asks for a pdf like the test code is.
To fix the issue, add to your #PostMapping annotation produces = MediaType.APPLICATION_PDF_VALUE see https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/bind/annotation/PostMapping.html#produces--
I am using Feign with the Apache Http Client and I would like to support the following jax-rs interface:
#POST
#Path("/do_something")
void doSomething(#QueryParam("arg") String arg);
But, ApacheHttpClient uses a RequestBuilder, which converts query parameters for requests without a body/entity into a UrlEncodedFormEntity.
I am converting my APIs to jax-rs, and I do not want to break backwards compatibility. Is there a way to use Feign without adjusting my API? Will the OkHttp or Ribbon clients support POSTs with query params and no body/entity? Is there another java jax-rs client that will support this?
Also, is there a reason why RequestBuilder turns query params into a UrlEncodedFormEntity? Is there an alternative HttpUriRequest builder within the apache-httpclient library that doesn't do this? RequestBuilder's build method has the following lines of code:
if (entity == null && (HttpPost.METHOD_NAME.equalsIgnoreCase(method) || HttpPut.METHOD_NAME.equalsIgnoreCase(method))) {
entity = new UrlEncodedFormEntity(parameters, HTTP.DEF_CONTENT_CHARSET);
} else {
// omitted expected behavior
}
Before switching to Feign, my code constructed a HttpUriRequest with something similar to the following:
URI uri = new URIBuilder()
.setScheme("https")
.setHost("localhost")
.setPath("service/do_something")
.addParameter("arg", "value")
.build();
HttpUriRequest request = new HttpPost(uri);
If you are willing to break the API slightly and maintain support for the #QueryParam, then you could define a request interceptor on the feign client that adds a plain text entity/body to the request:
.requestInterceptor(template -> {
if (template.method().equals(HttpPost.METHOD_NAME) && template.queries().keySet().size() > 0 && template.body() == null) {
template.body(" ");
}
})
Then, your API would change with the following:
#POST
#Consumes(MediaType.TEXT_PLAIN)
#Path("/do_something")
void doSomething(#QueryParam("arg") String arg);
But, this breaks the API since the server now expects/consumes a POST message with a plain text entity/body.
I think the same could be accomplished without the requestInterceptor and with Feign's #Body template:
#POST
#Consumes(MediaType.TEXT_PLAIN)
#Body(" ")
#Path("/do_something")
void doSomething(#QueryParam("arg") String arg);
But, this means that your API would have to include Feign rather than pure jax-rs annotations.
I am calling a micro-service in my rest controller. It works fine when ever there is a successful response from the Micro-service but if there is some error response I fails to pass on the error response back to user. Below is the sample code.
#GetMapping("/{id}/users/all")
public Mono<Employee> findAllProfiles(#PathVariable("id") UUID organisationId,
#RequestHeader(name = "Authorization", required = false) String oauthJwt) {
return webClient.get().uri(prepareUrl("{id}/users/all"), organisationId)
.header("Authorization", oauthJwt).accept(MediaType.APPLICATION_JSON)
.exchange().then(response -> response.bodyToMono(Employee.class));
}
Now if there is any JSON response with error code then web client does not pass on the error response to the controller due to which no information is propagated to the api end user.
You should be able to chain methods from the Mono API. Look for "onError" to see a number of options which allow you to define the behavior when there is an error.
For example, if you wanted to return an "empty" Employee, you could do the following:
.exchange()
.then(response -> response.bodyToMono(Employee.class))
.onErrorReturn(new Employee());
I have a spring boot application. I use a rest architecture.
I have this method.
#RequestMapping(value = "/members/card/{cardId}", method = RequestMethod.HEAD)
public ResponseEntity hasCardIdValid(#PathVariable(value = "cardId") String cardId) {
return memberService.hasCardIdValid(cardId) ? new ResponseEntity(HttpStatus.OK) : new ResponseEntity(HttpStatus.NOT_FOUND);
}
I another application, I would like to call hasCardIdValid method.
I wrote this code
HttpHeaders response = restTemplate.headForHeaders("/rest/members/card/{cardId}", cardId);
I don't find a way to get the 200 or 404 value from response. I don't see any method for that.
Is it possible?
This is because you are getting back HttpHeaders as a result of your restTemplate#headForHeaders() method call.
If you want to get hold of the status you'll have to invoke one of the RestTemplate#exchange() methods instead (there are a few overloaded method signatures) that is giving you back a ResponseEntity on which you can invoke getStatus().
I am new to RESTful services and their implementation on Spring 3. I would like your opinion on the best practices for returning type when a client creates a new resource in my server.
#RequestMapping(method = RequestMethod.POST,
value = "/organisation",
headers = "content-type=application/xml")
#ResponseStatus(HttpStatus.CREATED)
public ??? createOrganisation(#RequestBody String xml)
{
StreamSource source = new StreamSource(new StringReader(xml));
Organisation organisation = (Organisation) castorMarshaller.unmarshal(source);
// save
return ???;
}
A simple choice would be javax.ws.rs.core.Response, found in the Java EE's own restful services package. It - simply - tells what the web server should answer to the HTTP request.
For instance:
if (organisation != null)
return Response.ok().build();
else
return Response.serverError().build();
Custom response headers and other exotic things like that are possible with that return type too, but I don't think that would match with "best practices".
uh, I missed that #ResponseStatus(HttpStatus.CREATED)... I guess my answer was not much of help.
Maybe this will help instead: How to return generated ID in RESTful POST?
I would go for a ResponseEntity<byte[]> and you would have take care of the marshalling of your response on your controller method. Notice that you are basically scrapping the V in MVC, there is a MarshallingView on Spring but from experience I consider the previous solution much more flexible and easier to understand.
It is a good idea to return the newly created entity(with the generated id) wrapped in ResponseEntity. You can also set the HttpStatus in ResponseEntity based on the result of the operation.
#RequestMapping(method = RequestMethod.POST,
value = "/organization",
headers = "content-type=application/xml")
public ResponseEntity<Organization> createOrganisation(#RequestBody String xml) {
StreamSource source = new StreamSource(new StringReader(xml));
Organization organisation = (Organization) castorMarshaller.unmarshal(source);
// save
return new ResponseEntity<Organization>(organization, HttpStatus.OK);
}