이번 편의 목표: 없는 번호의 조회는 404로, 검증 실패는 짧은 JSON 메시지로 응답합니다.
기본 오류 본문은 길어서 API를 호출하는 쪽이 읽기 어렵습니다. 예외를 한곳에서 응답으로 바꿉니다.
없는 책
BookService.sample은 항상 샘플을 만들었습니다. 번호를 받아 없으면 예외를 던지도록 메서드를 추가합니다. 저장소는 다음 편에 붙이므로, 이 편에서는 1번만 있다고 가정합니다.
public Book find(Long id) {
if (id == null || id != 1L) {
throw new ResponseStatusException(
org.springframework.http.HttpStatus.NOT_FOUND,
"책을 찾을 수 없습니다.");
}
return new Book(1L, "샘플", 0);
}import로 org.springframework.web.server.ResponseStatusException 과 HttpStatus를 가져와도 됩니다. 컨트롤러의 find는 bookService.find(id)를 반환합니다. GET /api/books/2 는 404입니다. GET /api/books/1 은 샘플입니다.
검증 오류 형식
ApiExceptionHandler.java를 추가합니다.
package com.thinktree.library;
import java.util.Map;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice
public class ApiExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<Map<String, String>> handle(
MethodArgumentNotValidException exception) {
String message = "입력값을 확인해 주세요.";
if (!exception.getBindingResult().getFieldErrors().isEmpty()) {
String field = exception.getBindingResult().getFieldErrors().get(0).getField();
String reason = exception.getBindingResult().getFieldErrors().get(0).getDefaultMessage();
message = field + ": " + reason;
}
return ResponseEntity.badRequest().body(Map.of("message", message));
}
}@RestControllerAdvice는 컨트롤러 밖에서 예외를 응답으로 바꿉니다. 검증 실패의 첫 필드만 메시지에 담습니다. 빈 제목으로 POST하면 상태 400과 message 필드가 있는 JSON이 옵니다.
ResponseStatusException이 만드는 404는 이 클래스에서 다시 처리하지 않습니다. 상태 코드를 이미 예외에 담아 두었기 때문입니다.
직접 해 보기
없는 번호와 빈 제목을 각각 요청해 상태 코드가 404와 400으로 다른지 확인하세요.
해설
없는 번호는 find 안의 ResponseStatusException입니다. 빈 제목은 create 호출 전에 검증이 실패하고 ApiExceptionHandler가 400을 만듭니다. 정상 요청의 상태 코드는 아직 200입니다.
COMMENTS
댓글 0
이 글에 대한 의견이나 질문을 남겨 주세요.
댓글은 구글이나 카카오로 시작한 뒤에 남길 수 있습니다.
등록된 댓글이 없습니다.