POST 요청은 일반적으로 데이터를 body로 보낸다
@PostMapping(value = "/boards/{boardId}", params = "command=move")
public ResponseEntity<BoardDto> movePiece(@PathVariable int boardId, @RequestBody CommendDto commendDto) {
gameService.move(boardId, commendDto);
return ResponseEntity.ok(gameService.gameStateAndPieces(boardId));
}
처음에 위와 같이 코드를 짰었다. boardId에 해당하는 체스판을 CommandDto 안의 위치 정보를 통해 체스 말을 움직이는 요청을 처리한다.
그런데 위와 같은 피드백을 받았다. 체스판에서 어떤 행동을 할지 쿼리 파라미터로 분기하고 있었는데 이렇게 하기보단 경로 자체에서 기능을 분기하는 것이 좋을 것 같다는 피드백이었다.
처음엔 리뷰 받은데로 수정했다가 url에 동사를 넣는 것은 안티 패턴이라고 해서 HTTP 메서드를 다르게 하여 체스판을 움직이는 요청을 아래와 같이 처리했다.
@PutMapping("/boards/{boardId}")
public ResponseEntity<BoardDto> movePiece(@PathVariable int boardId, @RequestBody CommendDto commendDto) {
chessGameService.move(boardId, commendDto);
return ResponseEntity.ok(chessGameService.getBoardDtoByBoardId(boardId));
}
HTTP 메서드가 GET이었다면 단순히 체스판을 조회했을 것이고 POST였다면 체스판을 새로 생성하여 저장했을 것이다. 리소스의 수정을 요청하는 PUT 요청을 받았기에 체스판 안의 데이터를 수정하는 로직을 같은 url 정보에 다르게 분기시킬 수 있었다.
커스텀 예외는 만들어야할까?
체스 규칙에 맞지 않게 체스 말을 움직이거나 사용자가 잘못된 입력값을 입력했을 때와 같은 특수한 예외를 처리하기 위해 커스텀 예외를 만들었었다.
public class CustomException extends RuntimeException {}
public class UserInputException extends CustomException {}
public class IllegalChessRuleException extends CustomException {}
위와 같이 RuntimeException을 상속받은 CustomException을 UserInputException과 IllegalChessRuleException이 상속받고 있다.
이렇게 하면 사용자에게 보여줄 의미 있는 예외 상황만 전달할 수 있는 장점이 있었다.
이를 표준 예외로 처리했더라면 내가 예상하지 못한 예외 메시지까지 클라이언트에게 전달할 수 있다.
서버 상에서만 관리할 예외는 클라이언트에게 보여줄 필요가 없다고 생각하여 커스텀 예외의 메시지만 보여주도록 한 것이다.
@ExceptionHandler(CustomException.class)
public ResponseEntity<ErrorMessageDto> handleBadRequest(CustomException exception) {
return ResponseEntity.badRequest().body(new ErrorMessageDto(exception.getMessage()));
}
하지만 리뷰어가 커스텀 예외에 대한 단점을 물어봤고 아래와 같이 대답했다.
비즈니스 로직과 관련한 특수한 예외를 처리할 Exception을 만드는 것도 좋은 방법일 테지만 애플리케이션이 커진다면 많은 커스텀 예외가 만들어질 수도 있을 것 같아 사용하는 데 주의가 필요하다고도 느꼈다.
단건 조회에는 'LIMIT 1'로 성능 향상시키기
String sql = "select * from room where name = :name";
String sql = "select * from room where name = :name LIMIT 1";
삭제 쿼리를 날릴 때 정상적으로 삭제했을 때만 성공인 것일까?
@Override
public void deleteById(int id) {
String sql = "delete from room where id = :id";
jdbcTemplate.update(sql, Map.of("id", id));
}
DB의 데이터를 삭제하는 메서드를 위와 같이 작성했었다.
쿼리문에서 where문에 해당하는 조건의 데이터가 없다면 아무 일도 일어나지 않는다. 때문에 없는 데이터를 삭제하려고 하는 것에 대한 어떤 처리도 하지 않았다.
그런데 위와 같은 리뷰를 받았고 아래와 같이 대답했다.
컨트롤러의 메서드도 한 가지 책임만 갖게 하자
@PostMapping("/rooms/{roomId}")
public ResponseEntity<BoardDto> startNewGame(@PathVariable int roomId) {
return ResponseEntity.ok(gameService.startNewGame(roomId));
}
위 메서드는 게임을 새로 시작하는 책임과 체스판 데이터를 조회하는 두 가지 일을 하고 있다.
@PostMapping("/{roomId}")
public String startNewGame(@PathVariable int roomId) {
chessGameService.startNewGame(roomId);
return "redirect:/api/rooms/" + roomId;
}
리뷰를 반영하여 게임을 새로 시작하는 책임만 갖게 하고 조회하는 메서드로 redirect 시켰다.
'우아한테크코스' 카테고리의 다른 글
레벨 4 톰캣 만들기 미션 서버 소켓 코드 분석 (0) | 2022.09.03 |
---|---|
Level2 지하철 노선도 미션 피드백 정리 (feat. dao, repository) (0) | 2022.05.15 |
Level1 체스 미션 피드백 정리 (0) | 2022.04.10 |
수업 따라하기 (Gradle 프로젝트에 Docker로 mysql 접속) (0) | 2022.03.30 |
Level1 블랙잭 미션 피드백 정리 (0) | 2022.03.21 |