JsonResponse 클래스 및 RentResponse, ErrorResponse
public class JsonResponse {
private final int status; // HTTP 상태 코드
private final String message; // 에러 메시지
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
private LocalDateTime timestamp = LocalDateTime.now(); // 에러 발생 시간
}
public class RentResponse extends JsonResponse {
public RentResponse(int status, String message) {
super(status, message);
}
}
public class ErrorResponse extends JsonResponse {
public ErrorResponse(int status, String message) {
super(status, message);
}
}
기존에 RestController에서 값을 전달할 때, 이런 식으로 객체를 만들어서 전달했었다. JsonResponse라는 클래스로 다형성도 구현해서 나름 만족하고 사용하고 있었다.
실제 사용은 아래와 같이 사용했다.
@PostMapping("/{bookId}/rent")
public RentResponse rent(HttpSession session, @PathVariable("bookId") Long bookId, HttpServletResponse response) {
User user = (User) session.getAttribute("user");
Book findBook = bookService.findBookById(bookId);
if (user.rent(findBook)) {
return new RentResponse(
HttpServletResponse.SC_OK,
"정상적으로 대출되었습니다."
);
}
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
return new RentResponse(
HttpServletResponse.SC_BAD_REQUEST,
"대출되지 않았습니다."
);
}
다형성 측면에서는 나쁘지 않았지만, 중간에 status를 세팅해주어야 하고, 정상 대출 및 반납시에는 상태 코드를 생략해도 되었다. 실제로 클라이언트에서 중요하게 받는 것은 status와 message 였다.
const rent = id => {
fetch(`/books/${id}/rent`, {
method : "POST",
headers : {
"Content-Type": "application/json",
}
})
.then((res) => {
if (!res.ok) {
return res.json().then(body => {
throw new Error(`HTTP Error! status : ${body.status}, message : ${body.message}`)
})
}
return res.json();
})
.then((data) => alert("결과 : " + data.message))
.catch(error => alert(error.message));
};
강의를 듣다 보니, ResponseEntity 클래스를 사용하면, 좀 더 단순하게 세팅이 가능할 것 같았다. 그리고, status를 Response 객체에 넣는 것은 중복으로 불필요하게 값을 넘기는 것이었다. 단순히 http 상태 코드를 클라이언트에서 확인해서 처리하면 될 일이었다.
ResponseEntity<String> 으로 개선
그래서, ResponseEntity<String>을 반환하는 방법으로 개선했다.
@PostMapping("/{bookId}/rent")
public ResponseEntity rent(HttpSession session, @PathVariable("bookId") Long bookId) {
User user = (User) session.getAttribute("user");
Book findBook = bookService.findBookById(bookId);
log.debug("rent by user={}", user);
log.debug("rent findBook={}", findBook);
if (user.rent(findBook)) {
return new ResponseEntity<>("정상 대출 되었습니다.", HttpStatus.OK);
}
return new ResponseEntity<>("정상 대출 되지 않았습니다.", HttpStatus.BAD_REQUEST);
}
클라이언트에서도 보다 간결하게 메시지와 상태를 받아 처리할 수 있게 되었다.
const rent = id => {
fetch(`/books/${id}/rent`, {
method : "POST",
headers : {
"Content-Type": "application/json",
}
})
.then((res) => {
if (!res.ok) {
return res.text().then(body => {
throw new Error(`HTTP Error! status : ${res.status}, message : ${body}`)
})
}
return res.text();
})
.then((data) => alert("결과 : " + data))
.catch(error => alert(error.message));
};