todo 어플리케이션의 댓글 삭제 기능의 요구사항은 다음과 같았다.
작성한 코드
@DeleteMapping("/{commentId}")
fun deleteComment(
@PathVariable toDoId: Long,
@PathVariable commentId: Long,
@RequestBody request: DeleteCommentRequest
): ResponseEntity<Map<String, String>> {
commentService.deleteComment(toDoId, commentId, request)
return ResponseEntity
.status(HttpStatus.NO_CONTENT)
.body(mapOf("message" to "댓글이 삭제되었습니다."))
}
기대한 응답
HTTP/1.1 204 No Content
{"message" : "댓글이 삭제되었습니다."}
실제 응답
HTTP/1.1 204 No Content
Response Body의 값이 존재하지 않았다. 분명 ResponseEntity 의 body 부분에 값을 넣었는데 왜 보이지 않은걸까?
이유는 204 No Content라는 상태코드에 있었다.
The 204 (No Content) status code indicates that the server has successfully fulfilled the request and that there is no additional content to send in the response content.
https://www.rfc-editor.org/rfc/rfc9110#status.204
Http 명세서에 따르면 204 상태코드는 서버가 요청을 성공적으로 수행하고 응답으로 보낼 추가적인 내용이 없다는것을 나타낸다고 한다.
이 상태코드는 본문 없는 응답을 위한 상태 코드이지만, 서버에서 잘못되게 본문을 포함한 응답을 전달하는 경우가 존재할 수 있습니다. 이 프로토콜은 사용자 에이전트 다양한 방법으로 처리하는 것을 허용하고 있습니다.
https://developer.mozilla.org/ko/docs/Web/HTTP/Status/204
MDN 문서에서도 볼 수 있듯이 204 상태코드는 Response Body가 없는 것이 정상인것이다. 따라서 스프링에서 자체적으로 내용을 삭제하고 응답을 보내게 된다.
클라이언트에 메세지를 전달해야하기 때문에 body를 사용할 수 없는 204 No Content코드 대신 200 OK를 이용하기로 했다. 하지만 상태코드는 204임을 클라이언트에게 알려주어야 하기 때문에 메세지와 상태코드를 포함한 응답용 클래스를 따로 만들었다.
응답용 클래스
@JsonInclude(JsonInclude.Include.NON_NULL)
data class GeneralResponse(
val status: Int,
val message: String,
var data:Any? = null
)
data가 null일시 응답에 포함되지 않게 하기 위해 @JsonInclude를 사용하였다.
수정한 코드
@DeleteMapping("/{commentId}")
fun deleteComment(
@PathVariable toDoId: Long,
@PathVariable commentId: Long,
@RequestBody request: DeleteCommentRequest
): ResponseEntity<GeneralResponse> {
commentService.deleteComment(toDoId, commentId, request)
return ResponseEntity
.status(HttpStatus.OK)
.body(GeneralResponse(
HttpStatus.NO_CONTENT.value(),
"댓글이 삭제되었습니다."
))
}
ResponseEntity의 status는 200으로 설정하고 body에
요구사항에 맞게 상태코드와 메세지를 넣은 응답용 객체를 담아 반환하였다.
수정 후 응답
HTTP/1.1 200 OK
{
"status" : 204,
"message" : "댓글이 삭제되었습니다."
}
원하는 응답이 나온것을 확인할 수 있었다.