본문 바로가기
스프링

HTTP 메소드 PUT, FATCH 차이점(멱등성)

by 순원이 2024. 4. 11.

 

POST 메소드로 정순원이라는 이름1을 가진 학생을 생성하기 위에 아래와 같이 요청하면, 고유 구분값인 id를 1로 설정되어 이름1 학생이 생성된다.

HttpRequest
POST /student
{
  “name”: “이름1”,
  “grade”: 1
}

HttpResponse
HTTP/1.1 200 OK
{
  “id”: 1,
  “name”: “이름1”,
  “grade”: 1
}

그러면 이제, PUT을 통해 이름1의 grade를 2를 변경해보자. PUT은 리소스에 대한 수정이므로 특정 리소스를 구분하는 id값을 넣어줘야 한다.

HttpRequest
PUT /student/1
{
  “grade”: 2
}

HttpResponse
HTTP/1.1 200 OK
{
  “id”: 1,
  “name”: “뽀로로”,
  “grade”: 2
}

이는 POST와 PUT의 가장 기본적인 사용예제이고, 두 메서드의 차이를 조금 더 자세히 알아보기 위한 예제를 또 살펴보자.

POST 메서드로 이름1 학생을 생성해달라고 2번 요청하면 어떻게 될까?

POST /student
{
   “name”: “이름1”,
   “grade”: 1
}

id가 1과 2인 이름1 두 개가 생겨버린다. POST는 리소스를 생성하기 위한 메서드로 요청한 횟수마다 새로운 리소스를 생성한다.
(물론 name을 unique key로 잡으면 같은 이름으로 생성하지 안되게 만들 수는 있다.)

HTTP/1.1 200 OK
{ “id”: 1, “name”: “이름1”, “grade”: 1 }

HTTP/1.1 200 OK
{ “id”: 2, “name”: “이름1”, “grade”: 1}

반대로 PUT으로 같은 요청을 두번 보내면 어떻게 될까?

PUT /student/3
{
  “name”: ”이름2”
  “grade”: 2
}

2번 아니, 수백번 보내도 아래와 같이 같은 응답이 온다. id를 3을 가진 리소스는 없었으므로, 최소 한번은 생성되고, 그 후에는 생성되지 않는다.

HTTP/1.1 200 OK
{ “id”: ”3”, “name”: “이름2”, “grade”: 2 }

예시를 들며 설명했던 내용을 다시 정리해보면,

  • POST
    POST는 리소스의 생성을 담당한다.
    POST는 요청 시 마다, 새로운 리소스가 생성된다.
  • PUT
    PUT은 리소스의 생성과 수정을 담당한다.
    PUT은 요청 시 마다, 같은 리소스를 반환한다
    * 물론, 리소스 안에 속성은 변경될 수 있다.

이를 어려운 말로 이야기하면, PUT은 멱등하다고 말할 수 있고, POST는 멱등하지 않다라고 말한다.

컴퓨터 과학에서 멱등하다는 것은 첫 번째 수행을 한 뒤 여러 차례 적용해도 결과를 변경시키지 않는 작업 또는 기능의 속성을 뜻한다.

[ Patch와 Put의 차이점 ]

PATCH는 수정만 담당하며 리소스의 일부분만 수정할 때 사용하고, PUT은 리소스의 모든 속성을 수정하기 위해 사용한다.

 

[ HTTP 메소드의 멱등성이 필요한 이유 ]

HTTP 멱등성이 필요한 이유는 요청의 재시도 때문이다. 만약 HTTP 요청이 멱등하다면, 요청이 실패한 경우에 주저없이 재시도 요청을 하면 된다. 하지만 만약 HTTP 요청이 멱등하지 않다면, 리소스가 이미 처리되었는데 중복 요청을 보낼 수 있다. 예를 들어 이미 결제된 요청인데, 중간에 연결이 끊겨서 다시 결제 요청을 보내서 문제를 일으킬 수 있는 것이다. 그래서 클라이언트는 무지성으로 재시도 요청을 보내면 안되고, 멱등성을 고려하여 재시도 요청을 해야 한다.

 

[ PATCH 메소드가 멱등하지 않은 이유 ]

예를 들어 name에 해당하는 값을 변경하고자 할 때 PATCH를 사용할 수 있다. 예를 들어 우리는 아래와 같이 요청을 N번 날려도 항상 동일한 결과를 응답받게 된다. 

  1. PATCH → {name: ”MangKyu”}
  2. PATCH → {name: ”MangKyu”}

 

그래서 PATCH를 멱등하다고 착각할 수 있는데, 문제는 PATCH가 보다 범용적으로 사용된다는 것이다. 예를 들어 “name” 필드를 보내면 값을 추가(append)하는 요청 역시 PATCH가 사용된다. 그러면 PATCH 요청에 의한 결과는 매번 달라지게 될 것이다. 그러므로 PATCH 메소드는 항상 멱등하다고 볼 수 없다.

  1. PATCH → name: [”MangKyu”]
  2. PATCH → name: [”MangKyu”, ”MangKyu”]
  3. PATCH → name: [”MangKyu”, ”MangKyu”, ”MangKyu”]

 

[ DELETE 메소드가 멱등한 이유 ]

예를 들어 자원이 있는 상태에서 우리가 다음과 같이 사용자 삭제 요청을 보냈다고 하자. 처음에는 성공 응답(200)을 받았지만, 동일한 요청을 보냈더니 에러 응답(404)을 받은 것이다.

  1. DELETE → 200 OK
  2. DELETE → 404 NOT FOUND

 

DELETE를 사용하면 클라이언트가 받는 응답 상태 코드가 달라질 수 있음에도 불구하고 DELETE 메소드는 멱등하다. 왜냐하면 멱등성의 기준이 “상태 코드”가 아니기 때문이다. 앞서 살펴본대로 공식 문서의 설명에 따르면 멱등성은 “서버에 미치는 의도된 영향이 동일한가?” 이다. DELETE의 목적은 리소스를 삭제하여 서버에 리소스가 없도록 만드는 것이고, DELETE를 여러 번 호출해도 응답 상태와 무관하게 리소스가 없는 상태를 유지하도록 한다. 그러므로 HTTP DELETE 메소드는 멱등한 것이다.

결국 멱등성은 리소스 관점에서 생각하는 것이 중요하다. 여러 번 요청해도 리소스가 동일하다면 멱등한 것으로 봐도 된다.