HTTP와 Restful에 대해 공부하면 GET
, POST
를 넘어서 PUT
, DELETE
같은 다양한 HTTP 메소드들을 만나게 된다. PUT
은 보통 리소스를 업데이트하기 위해 많이 사용하고, 몇번을 요청해도 동일한 결과를 보여주는 멱등성을 띈다. 인터넷에 보면 수 많은 사람들이 내가 했던 것과 똑같은 오해를 하길래, 오늘은 그 동안 내가 PUT
메소드에 대해 착각하고 있던 점이 있어 정리하려고 한다.
내가 착각하고 있던 부분이 바로 위와 같은 생각이다. 결론부터 말하자면 상황에 따라 다르다. 일단 PUT 요청이 들어오면 타겟 리소스가 없을 시 해당 리소스를 생성할 수 있는 것은 맞다. HTTP/1.1 스펙을 정리한 rfc7231 문서에는 다음과 같이 기술되어 있다.
The PUT method requests that the state of the target resource be
created or replaced with the state defined by the representation
enclosed in the request message payload
-- rfc7231
"??? 뭐야 없으면 생성하고 있으면 수정하는거 맞잖아??"싶다면, 밑에서 더 자세히 설명하겠다
내가 착각1을 하게된 원인이었다. 나는 PUT
은 멱등성을 가지기 때문에 당연히 리소스가 없으면 생성하고 있으면 수정해서 404 같은 에러를 발생하면 안된다고 생각하고 있었다. 하지만 생각해보면 아니라는걸 알 수 있다. 리소스가 없어서 계속 404를 반환해도 멱등성은 유지된다. 멱등성이란 서버(및 데이터) 상태가 동일할때 여러번 요청을 보내도 동일한 결과가 나온다는 뜻일 뿐이다.
기획 의도와 요청 의도에 따라 PUT API는 존재하지 않는 타겟 리소스에 대해 요청이 들어왔을때 리소스를 생성할 수도 있고, 생성하지 않을 수도 있다. 서비스가 상태를 변경 시키는 요청을 받았을때 클라이언트 대신 제대로된 URI를 선택해준다면 PUT
대신에 POST
가 사용되어야한다.
Proper interpretation of a PUT request presumes that the user agent
knows which target resource is desired. A service that selects a
proper URI on behalf of the client, after receiving a state-changing
request, SHOULD be implemented using the POST method rather than PUT.
If the origin server will not make the requested PUT state change to
the target resource and instead wishes to have it applied to a
different resource, such as when the resource has been moved to a
different URI, then the origin server MUST send an appropriate 3xx
(Redirection) response; the user agent MAY then make its own decision
regarding whether or not to redirect the request.
-- rfc7231
일반적인 게시판 서비스를 만든다고 해보자. 다음과 같은 API가 있을 수 있다.
POST /posts --> 게시글을 생성한다. 게시글 id를 DB에 의해 자동 생성된다
PUT /posts/{id} --> 해당 게시글을 수정한다
이때 PUT /posts/{id}
API는 게시글이 존재하지 않을때 생성해야할까? id
는 DB에 의해 생성되며 클라이언트는 게시글을 POST
요청을 통해 생성하기 전에는 이를 알 수 없다. 그렇기 때문에 PUT /posts/{id}
API로 존재하지 않는 게시글의 id
로 접근한다면, 이는 해당 타겟 리소스를 생성하려는 의도보다는 잘못된 게시글 id를 보낸것이다. 따라서 404 에러를 반환해야한다.
반대로 어떤 경우에 PUT
을 통해 리소스를 생성할 수 있을까? 클라이언트가 id
를 특정해 생성할때 사용할 수 있다. 학생을 학번으로 특정할 수 있는 다음과 같은 API를 생각해보자.
PUT /students/{studentId} --> 학번의 학생을 생성하거나 수정한다
학번은 자동 생성하지않고, 학번을 특정해서 요청을 보내는 것의 의도가 게시글과는 다르기 때문에 POST
메소드로 생성하기에는 적합하지 않지 않을 수 있다. 따라서 PUT
메소드를 사용해 생성 및 수정을 할 수 있다.
이게 궁금햇어요