PutMapping 은 수정하기 인데, 왜 CREATED 가 있는것인지,
여기서 @Valid 는 @RequestBody 만 @Valid 하는 것인지, 아니면 @PathVariable 까지 포함해서 @Valid 하는 것인지.
book.set~~() 을 해서 수정되는 데이터를 교체해줬는데, 왜 book=bookService.save(book); 을 해주는것인지,
그리고 save 를 해주게 되면, id 값은 새롭게 부여되는것인지,
아니면 id 값은 그대로 있고 @PrePersist 인 createdAt 의 값만 LocalDateTime.now() 를 받아서
새롭게 부여되는것인지가 궁금해.
질문에 대한 답변:
1. @PutMapping과 HttpStatus.CREATED의 조합:
- **@PutMapping**은 일반적으로 리소스를 수정할 때 사용됩니다.
- 그러나 여기서 HttpStatus.CREATED를 사용하는 것은 약간 이상합니다. **HttpStatus.CREATED**는 새 리소스가 생성되었음을 나타내기 때문에 일반적으로 @PostMapping과 함께 사용됩니다.
- 이 코드에서는 수정 작업을 수행하므로, HttpStatus.OK나 HttpStatus.NO_CONTENT가 더 적합할 것입니다.
2. @Valid의 적용 범위:
- @Valid는 @RequestBody에만 적용됩니다.
- 즉, BookPayloadDTO 클래스의 유효성 검사를 수행합니다.
- @PathVariable에는 별도로 유효성 검사를 적용하지 않습니다.
- 만약 @PathVariable에도 유효성 검사가 필요하다면, 커스텀 Validator나 다른 유효성 검증 메커니즘을 추가로 구현해야 합니다.
3. book.set~~() 후 book = bookService.save(book);을 호출하는 이유:
- book.set~~()으로 데이터 값을 변경했지만, 변경된 엔티티를 영속화(Persistence) 계층에 저장하려면 save()를 호출해야 합니다.
- JPA의 영속성 컨텍스트는 엔티티의 상태를 추적합니다.
- save()를 호출하면 변경된 엔티티가 데이터베이스에 반영됩니다.
- save()는 다음과 같은 작업을 수행합니다:
- 새로운 엔티티: 데이터베이스에 새로 삽입.
- 기존 엔티티: 데이터베이스에서 수정(Update).
4. save()를 호출하면 id 값은 어떻게 되는지:
- id 값은 유지됩니다:
- JPA는 id 필드를 기준으로 엔티티가 새로운 것인지 기존 것인지 판별합니다.
- id가 이미 존재하는 경우, 해당 엔티티는 "수정" 작업으로 처리되며, 새로운 id가 부여되지 않습니다.
- 그러나 @PrePersist가 아닌 **@PreUpdate**가 적용되면 수정 시 createdAt이 변경되지 않고, updatedAt 필드를 별도로 관리하는 것이 일반적입니다.
5. @PrePersist와 createdAt의 동작:
- **@PrePersist**는 새 엔티티가 처음으로 저장되기 전에 호출됩니다.
- 수정 시에는 **@PreUpdate**를 사용하는 것이 일반적입니다.
- 따라서, 수정 작업에서 createdAt 필드가 변경되지 않고 유지되려면, 수정 시에는 @PrePersist가 작동하지 않도록 해야 합니다.
- 수정 시 LocalDateTime.now()로 createdAt이 갱신된다면 이는 잘못된 동작입니다.
- 수정 시점의 시간을 기록하려면 별도의 updatedAt 필드를 추가하고, @PreUpdate를 사용해야 합니다.
개선 제안:
- HttpStatus.CREATED를 HttpStatus.NO_CONTENT 또는 HttpStatus.OK로 변경:
- @PutMapping에 맞는 상태 코드를 사용하는 것이 RESTful 원칙에 적합합니다.
- createdAt 필드 유지:
- @PrePersist 대신 수정 전에는 @PreUpdate를 사용하고, createdAt을 변경하지 않도록 로직을 수정하세요.
- updatedAt 필드 추가:
- 수정 시점을 저장하려면 updatedAt 필드를 추가하고 @PreUpdate로 관리하는 것을 권장합니다.
- 유효성 검증:
- @PathVariable에도 유효성 검증이 필요하다면 커스텀 유효성 검증 로직을 추가하거나, 별도의 어노테이션을 사용하는 것을 고려하세요.
DeleteMapping 은 삭제하기 인데, 왜 CREATED 가 있는것인지,
그리고 id 값을 받았으면 그걸로 해당 id 값의 정보가 있는 isPresent 로 확인을 했으면,
그리고 나서는 id 값으로 delete를 하면 되는데, 여기서는 굳이 왜 Book book;,book=optionalBook.get(); 이 있는걸까?
// 내 생각에는,
@DeleteMapping(value = "/books/{id}")
@ApiResponse(responseCode = "202", description = "Book deleted")
@Operation(summary = "Book delete")
public ResponseEntity<?> delete_Book(@PathVariable Long id){
Optional<Book> optionalBook=bookService.findById(id);
if(optionalBook.isPresent()){
bookService.deleteById(id);
return ResponseEntity.status(HttpStatus.ACCEPTED).body(null);
}else{
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null);
}
}
//이렇게 하면 될거 같은데, 아닌가?
1. @ResponseStatus(HttpStatus.CREATED)가 적절하지 않은 이유
- HttpStatus.CREATED는 새로운 리소스가 생성되었음을 의미합니다.
- 삭제 작업(@DeleteMapping)에는 HttpStatus.CREATED는 부적합합니다.
- 삭제 작업에서는 일반적으로 HttpStatus.NO_CONTENT (204) 또는 **HttpStatus.ACCEPTED (202)**를 사용하는 것이 RESTful API 설계 원칙에 맞습니다.
2. Book book 변수와 optionalBook.get() 호출의 불필요성
- 코드에서 Book book 변수와 optionalBook.get() 호출은 실질적으로 불필요합니다. 이유는 다음과 같습니다:
- 삭제 작업에서는 엔티티의 필드나 값 자체를 활용하지 않고, 단순히 ID를 기준으로 삭제 작업을 수행합니다.
- optionalBook.isPresent()로 해당 ID의 존재 여부만 확인하면 충분하며, 객체를 가져올 필요는 없습니다.
3. 추가적으로 고려할 사항
- HttpStatus.BAD_REQUEST의 적합성:
- BAD_REQUEST (400)은 보통 클라이언트 요청 자체가 잘못되었을 때 사용하는 상태 코드입니다.
- 여기서는 삭제하려는 ID가 존재하지 않는 경우이므로, **HttpStatus.NOT_FOUND (404)**가 더 적합할 수 있습니다.
최종 개선 코드:
@DeleteMapping(value = "/books/{id}")
@ApiResponse(responseCode = "202", description = "Book deleted")
@Operation(summary = "Book delete")
public ResponseEntity<?> delete_Book(@PathVariable Long id) {
if (bookService.findById(id).isPresent()) {
bookService.deleteById(id);
return ResponseEntity.status(HttpStatus.ACCEPTED).body(null);
} else {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("Book not found");
}
}
4. 이 코드의 장점
- 불필요한 변수 제거: Book book 변수를 선언하지 않음으로써 간결한 코드를 작성.
- 적합한 상태 코드 사용:
- 리소스 삭제 성공 시 202 ACCEPTED.
- 삭제 대상이 없을 경우 404 NOT_FOUND를 반환.
- 더 간결하고 직관적: 논리 흐름이 더 명확하며, 코드 가독성이 향상됩니다.
swagger 에서 확인해보고 테스트도 해보자.
실제 DB 에도 수정이 되었다는 걸 MySQL workbench 에 들어가서 확인해보자.
삭제 DELETE 도 해보자.
202 는 ACCEPTED 의 응답코드/상태코드이다. @DeleteMapping 의 return 을 보면 ACCEPTED 가 있다.
id 2 에 해당하는 데이터가 삭제가 되어 있는 것까지 확인 완료!
책의 이미지를 서버에다가 업로드하고 다운로드하는 RESTful,
Table 을 지금은 1개인데, 다른 table 을 여러 개 만들어서 관계 설정까지 해보는 것까지 해볼 것이다.
다음 게시물로.
'Spring Boot (+ RESTful)' 카테고리의 다른 글
RESTful 웹 서비스 구축 - # Project 04 - 이미지 업로드 (1) (0) | 2025.01.03 |
---|---|
RESTful 웹 서비스 구축 - @ControllerAdvice / @ExceptionHandler (1) | 2025.01.02 |
RESTful 웹 서비스 구축 - @GetMapping / responseCode (0) | 2024.12.31 |
RESTful 웹 서비스 구축 - @PostMapping / @RequestBody / swagger (0) | 2024.12.30 |
RESTful 웹 서비스 구축 - @PrePersist / DTO 구분 (Entity, Payload, View) (2) | 2024.12.24 |