Validating if request body in HTTP POST request is null in Spring Boot controller

天涯浪子 提交于 2020-08-10 20:15:07

问题


I am replacing manual validation of input to a POST request in a Spring Boot REST-controller. JSR-303 Spring Bean Validation is used for validating the instance variables in the request body and this is working as expected. What is the recommended method to validate that the object in the request body is not null?

I have tried:

  • annotating the entire object such as this: @NotNull @Valid @RequestBody Foo foo

  • annotating the entire class with @NotNull

I am replacing:

@PostMapping...
public ResponseEntity<Map<String, Object>> editFoo(
@RequestBody Foo foo, ...) {
   if(foo == null) {
      return (new ResponseEntity<>(headers, HttpStatus.BAD_REQUEST));
   }
}

with a Bean Validation equivalent:

@PostMapping...
public ResponseEntity<Map<String, Object>> editFoo(
@Valid @RequestBody Foo foo, ...) {
   ...
}

I tried unit testing the controller method by:

// Arrange
    Foo foo = null;
    String requestBody = objectMapper.writeValueAsString(foo);

    // Act + assert
    mockMvc
    .perform(
    post("/end_point")
    .contentType("application/json")
    .content(requestBody))
    .andExpect(status().isBadRequest());

I expected a MethodArgumentNotValidException which is handled by a @ControllerAdvice for this exception, but I get HttpMessageNotReadableException when executing the unit test. My questions:

  1. is it necessary to test if the request body is null?
  2. if 1. is true, how should this be done with Bean Validation?

回答1:


Seeing your code, you already check if the body is null. In fact @RequestBody has a default parameter required which defaults to true. So no need for Bean validation for that !

Your main issue here seems to be in your test. First of all it is good to write a test to validate your endpoint behavior on null.

However, in your test you does not pass null. You try to create a Json object from a null value with your objectMapper. The object you are writting seems not to be a valid json. So when your sending this body, Spring says that it cannot read the message, aka the body of your request, as you say it is a application/json content but there is not json in it.

To test null body, just send your request in your test just removing the .content(requestBody) line and it should work !

--- Edit 1 I thought it was rejecting the message because of the body, but in fact it seems to work right away for me. Here is my controler and test so you can compare to your full code :

@RestController()
@RequestMapping("end_point")
public class TestController {

    @PostMapping
    public ResponseEntity<Map<String, Object>> editFoo(@RequestBody Foo foo) {
       // if(foo == null) {
       //     return (new ResponseEntity<>(new HashMap<>(), HttpStatus.BAD_REQUEST));
       // }

        return (new ResponseEntity<>(new HashMap<>(), HttpStatus.OK));
    }
}


@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
public class TestControllerTest {
    @Autowired
    private MockMvc mvc;

    @Autowired
    private ObjectMapper objectMapper;

    @Test
    public void test_body_is_null() throws Exception {

        Foo foo = null;
        String requestBody = objectMapper.writeValueAsString(foo);

        // Act + assert
        mvc
            .perform(
                post("/end_point")
                    .contentType("application/json")
                    .content(requestBody))
            .andExpect(status().isBadRequest());
    }
}

This was made using Spring Boot 2.1.6.RELEASE

--- Edit 2 For the record if you want to use validation for null here, here is a snippet of the controller :

@RestController()
@RequestMapping("end_point")
@Validated
public class TestController {

    @PostMapping
    public ResponseEntity<Map<String, Object>> editFoo(@NotNull @RequestBody(required = false) Foo foo) {

        return (new ResponseEntity<>(new HashMap<>(), HttpStatus.OK));
    }
}

First you have to set required to false for the body, as default is true. Then you have to add the @NotNull annotation on the request body and @Validated on the controller. Here if you launch your test you will see that the request fails with :

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is javax.validation.ConstraintViolationException: editFoo.foo: must not be null

As you said you had a @ControllerAdvice you can then map the exception as you wish !



来源:https://stackoverflow.com/questions/57038083/validating-if-request-body-in-http-post-request-is-null-in-spring-boot-controlle

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!