(개인적인 생각이 들어가 있습니다. 틀린 내용이라면 지적부탁드립니다! )
상황 : 댓글에 좋아요를 누르기
좋아요 예외처리를 하던 도중, 어떤 댓글에 대하여 좋아요를 눌렀던 회원이 어떠한 오류(?)로 인해 좋아요를 또 누르는 요청을 보내는 경우 서버의 응답 상태코드는 무엇이 되어야 하는지 고민하게 되었습니다. 좋아요를 누르겠다는 요청은 제대로 들어온것이지만 누른 기록이 있기 때문에 할 수 없다는 에러처리를 발생시켜야 되겠다고 생각했습니다.
과정
HTTP 응답코드는 클라이언트에게 서버의 처리 상태를 알려주는 중요한 정보이기 때문에 해당 상황에서는 어떤 값을 넘겨주어야하는지 찾아보았습니다.
처음에 고려했던 응답 상태 코드는 총 3개였습니다.
- 400 (Bad Request) : 요청 자체가 잘못되었을 때 사용하는 코드.
💬 :좋아요 요청은 제대로 들어온것인데 요청 자체가 잘 못 들어온 것은 아니기 때문에 400 에러는 아니라고 생각했습니다. - 404 (Not Found): 찾는 리소스가 없다는 의미.
💬: 이 또한 마찬가지로 찾는 리소스가 없다는 의미와는 거리가 멀기때문에 올바르지 않다고 생각했습니다. - 409 (Conflict): 사용자의 요청이 서버의 상태와 충돌하여 응답하는 코드.
❕: 이 응답상태 같은 경우는 정의가 굉장히 애매하게 들렸습니다. 충돌하는 경우가 정확이 어떤 것인지 잘 몰랐기 때문이죠. 따라서 구글링을 통해서 409 에러를 내는 상황은 무엇이 있는지 찾아보기로 하였습니다.
한 StackOverFlow에서 저와 비슷한 질문을 한 게시글을 보게되었습니다. 요약해 보자면 다음과 같습니다.
(rest - HTTP response code for POST when resource already exists - Stack Overflow)
POST 메소드로 클라이언트가 객체를 만들 수 있도록 하려한다.
POST는 " 추가 " 라는 작업을 의미하는데 만약 객체가 이미 존재할 경우에는 어떻게 처리해야되나?
요청을 수정 요청으로 처리해야하는지 아니면 어떤 오류코드를 반환되나?
이 글의 댓글들을 보면 많은 의견들이 있습니다. 409..403….422 이 댓글들이 정답일 수 있고 아닐 수도 있지만 왜 해당 응답 상태코드를 써야 하는지 파악해보려고 했습니다. 그중에서 저의 생각과 가장 유사한 답글을 볼 수 있었습니다.
따라서 왜 409 confilct가 맞는지 에 대한 생각결과를 적어보겠습니다.
이유
먼저 결과로 동일한 식별자를 가진 리소스가 이미 존재하는 경우 “ 새로운 리소스 추가” 작업의 실패를 보고하는데 가장 적합한 상태코드는 HTTP 409 라고 생각합니다. RFC7231의 내용을 보면 409 Confilct에 대한 설명을 볼 수 있습니다.
The 409 (Conflict) status code indicates that the request could not be completed due to a conflict with the current state of the target resource.
409 (Conflict) 상태 코드는 대상 리소스의 현재 상태와 충돌하여 요청을 완료할 수 없음을 나타낸다고 나와있습니다.
여기서 주목해야될점은 타켓 리소스와 타켓 리소스의 현재 상태입니다.
RFC 7231 의 리소스 설명에 의하면
The target of an HTTP request is called a "resource". HTTP does not
limit the nature of a resource; it merely defines an interface that
might be used to interact with resources. Each resource is
identified by a Uniform Resource Identifier (URI), as described in
Section 2.7 of [RFC7230].
HTTP 요청의 대상을 ‘리소스(자원)’라고 표현하고 있습니다.
또한 리소스의 대한 상태는 요약해보자면
Considering that a resource could be anything, and that the uniform interface provided by HTTP is similar to a window through which one can observe and act upon such a thing only through the communication of messages to some independent actor on the other side, an abstraction is needed to represent ("take the place of") the current or desired state of that thing in our communications. That abstraction is called a representation [REST].
For the purposes of HTTP, a "representation" is information / that is intended to reflect a past, current, or desired state of a given resource,/ in a format that can be readily communicated via the protocol,/ and that consists of a set of representation metadata and a potentially unbounded stream of representation data.
HTTP는 어떤 자원을 다루기 위해 메시지를 주고받는 방식으로 동작합니다.
이때 자원은 다양한 것들이 될 수 있으며, 이를 메시지로 표현하기 위해 추상화가 필요합니다.
이 추상화를 "표현"이라고 하며, 표현은 자원의 현재 상태나 원하는 상태를 나타내는 정보를 말합니다.
이 정보는 HTTP 프로토콜로 쉽게 전송할 수 있는 형식으로 구성되며, 표현 메타데이터와 데이터 스트림으로 이루어집니다.
결론적으로 요약해 보자면 메타데이터(헤더)/ 데이터(payload)로 구성된 리소스 표현은 리소스의 상태를 반영한다는 것으로 요약해 볼 수 있습니다. 따라서 저는 URI로 표현된 리소스 표현이 상태를 반영하기 때문에 저장하려고 하는 값이 있는 경우 그 경우는 리소스 충돌이라고 생각했습니다.
예를 들어 , 저의 HTTP 요청으로 설명해 보겠습니다.
저의 경우 좋아요 기록을 저장해 달라는 HTTP 요청은 이러합니다.
post <http://localhost:8080/comments/3/likes?userId=c109>
userId가 c109인 3번 댓글에 대한 좋아요 기록을 저장해 달라는 의미를 가지고 있습니다.
과정을 살피면 다음과 같습니다.
- /comments/3/likes? username=c109라는 URI로 POST 요청을 보내어 "좋아요" 기록을 생성합니다.
- 이 URI는 "likes"라는 리소스를 가리키는데, 이 리소스는 "좋아요 기록"들의 컬렉션으로 이해할 수 있습니다. 따라서 이 리소스에는 여러 개의 "좋아요 기록" 객체들이 존재할 수 있습니다.
- 그리고 이 "likes" 리소스는 모든 "좋아요 기록"에 대한 정보를 포함하고 있습니다. 이제 새로운 "좋아요 기록" 객체를 생성하기 위해 POST 요청을 보내었습니다. 이때 생성하려는 "좋아요 기록" 객체의 댓글 ID는 3, 유저네임은 "c109"으로 지정하였습니다.
- 하지만 이미 존재하는 URI라면 "likes" 리소스는 POST 요청을 실패하게 됩니다. 왜냐하면 "likes" 리소스는 이미 존재하는 "댓글 ID 3, 유저네임 c109"을 포함하고 있기 때문입니다.
결론
따라서 요청한 리소스가 이미 존재하는 경우에는 서버가 충돌 상태(409 Conflict)를 응답하여 요청이 실패하게 됩니다. 해당 리소스가 이미 존재하는 상태이기 때문에, 클라이언트가 요청한 작업을 수행할 수 없기 때문이죠. 결론적으로 저의 경우 타켓 리소스의 현재 상태와 충돌한다는 의미에서 409 Conflict 상태 코드를 사용하여 처리하였습니다.
'Dev Diary' 카테고리의 다른 글
[2023 우아콘] 테크 리더 3인이 말하는 "개발자 원칙" (0) | 2023.03.30 |
---|---|
TestCode ? 왜 작성하는거야? (0) | 2023.03.05 |
[시작] 개발 일기(?)를 작성해보려고 합니다. (2) | 2023.02.11 |