Reputation: 151
After creating a service using Spring HATEOAS and testing it with mockmvc (also to generate documentation using Spring restdocs) we found the following.
Our RestController looks something like:
@RestController
@RequestMapping("/v1/my")
@ExposesResourceFor(My.class)
@EnableHypermediaSupport(type = EnableHypermediaSupport.HypermediaType.HAL)
public class MyController {
@Autowired
private MyRepository myRepository;
@Autowired
private MyResourceAssembler myResourceAssembler;
@RequestMapping(path = "", method = POST, consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
public HttpEntity<Resource<MyResource>> addMy(
@RequestBody MyResource newMyResource) {
if (myRepository.existsByMyId(newMyResource.getMyId())) {
return new ResponseEntity<>(HttpStatus.CONFLICT);
}
val newMy = new My(
null, // generates id
newMy.getMyId()
);
val myResource = myResourceAssembler.toResource(myRepository.save(newMy));
val resource = new Resource<>(myResource);
return new ResponseEntity<>(resource, HttpStatus.CREATED);
}
}
To test this we have created the following test:
@Test
public void addMy() throws Exception {
this.mockMvc.perform(post("/v1/my")
.content("{ \"myId\": 9911 }")
.contentType(MediaType.APPLICATION_JSON_UTF8)
.accept(MediaTypes.HAL_JSON))
.andExpect(status().isCreated())
.andExpect(MockMvcResultMatchers.jsonPath("$.myId").value(9911))
.andDo(this.document.document(selfLinkSnippet, responseFieldsSnippet));
}
The unit test result we get is:
java.lang.AssertionError: Status
Expected :201
Actual :415
Status code 415 is Media Type unsupported.
If we modify the unit test to say:
.contentType(MediaTypes.HAL_JSON)
The unit test returns success. Which is strange since we indicated to consume only application/json. The problem now is that the documentation that is generated, incorrectly states that the POST request should use Content-type application/hal+json:
curl 'http://my-service/v1/my' -i -X POST -H 'Content-Type: application/hal+json' -H 'Accept: application/hal+json' -d '{ "myId": 9911 }'
And if you try that, you will get another 415. If we change the Content-Type: to application/json, then it does work.
If we tell the method to consume both HAL+JSON and JSON:
@RequestMapping(path = "", method = POST, consumes = { MediaTypes.HAL_JSON_VALUE, MediaType.APPLICATION_JSON_UTF8_VALUE})
Then the unit test succeeds when contentType(MediaTypes.HAL_JSON) is set, but fails when contentType(MediaType.APPLICATION_JSON_UTF8) is set.
However, now the service both accepts application/json AND application/hal+json, such that the documentation is at least working.
Does anyone know why this is?
Upvotes: 0
Views: 3143
Reputation: 151
I found another stackoverflow question: Spring MVC controller ignores "consumes" property
And the solution there worked for me as well. I added the @EnableWebMvc to the test configuration class.
@EnableWebMvc
@Configuration
@Import({CommonTestConfiguration.class})
@EnableHypermediaSupport(type = EnableHypermediaSupport.HypermediaType.HAL)
public class MyControllerTestConfiguration {
@Bean
public MyRepository myRepository() {
return new InMemoryMyRepository();
}
@Bean
public MyController myController() {
return new MyController();
}
@Bean
public MyResourceAssembler myResourceAssembler() {
return new myResourceAssembler();
}
}
Upvotes: 0