Search code examples
javaspringspring-restcontroller

How can I escape null check when call a API?


When I write RestController in Spring, all time I check whether object is null or not. How can I escape this check?

In below example, there is null check and later return notFound or Http status 404. So I don't want to check it all time.

  @GetMapping(path = "/api/member/{member-id}")
  public ResponseEntity<Member> getMemberById(@PathVariable(name="member-id", required=true) final Long memberId) {
    final Member member = memberService.findById(memberId);
    if (member != null) {
      return ResponseEntity.ok(member);
    }
    return ResponseEntity.notFound().build();
  }

Solution

  • Although you cannot avoid the null-check itself, you can move it out of the Controller into the service (also, use Optional). If you are looking for a general strategy to handle negative response scenarios, I'd suggest using Spring's RestControllerAdvice annotation that will enable global exception handling for all your APIs:

    Let's first move the check to the service and raise a custom exception MemberNotFoundException in case no record is found.

    DefaultMemberService.java

    public Member findById(final String memberId) {
      Optional<Member> member = memberRepository.findById(memberId);
      return member.orElseThrow(() -> new MemberNotFoundException("Invalid member Id"));
    }
    

    In the Controller, just make a call to the service method, and return the response.

    MemberController.java

    @GetMapping(path = "/api/member/{member-id}")
    public ResponseEntity<Member> getMemberById(@PathVariable(name="member-id", required=true) final Long memberId) {
    
      return ResponseEntity.ok().body(memberService.findById(memberId));
    }
    

    As you can see, we're not handling the exception explicitly. Instead we'll let RestControllerAdvice do it for us by mapping the exception class to the response (error message, response code):

    ExceptionHandlerControllerAdvice.java

    @RestControllerAdvice
    public final class ExceptionHandlerControllerAdvice {
    
      @ExceptionHandler({ MemberNotFoundException.class })
      @ResponseStatus(HttpStatus.NOT_FOUND)
      ResponseEntity<ErrorDto> handleRecordNotFound(MemberNotFoundException ex) {
        return ResponseEntity.status(HttpStatus.NOT_FOUND)
            .body(new ErrorDto(ex.getMessage));
      }
    }
    

    where, ErrorDto (simplified) is:

    public class ErrorDto {
      private String message;
    
      public ErrorDto(String msg) { this.message = msg; }
    
      public String getMessage() { return this.message; }
    }
    

    Ref: RestControllerAdvice, ExceptionHandler