[ RESTful API] PUT과 PATCH의 차이 - 멱동성을 보장하는 PUT, 멱등성을 보장하지 않는 PATCH

2020. 6. 5. 13:46프로그래밍/프로그래밍 이것저것

PUT 메소드는 반드시 멱등성을 보장하지만 PATCH 메소드는 멱등성을 보장하지 않을 수도 있다.


멱등성이란

멱등성이란 어떤 대상에 같은 연산을 여러번 적용해도 결과가 달라지지 않는 성질이다.
HTTP 메소드 외에도 데이터베이스나 파일에 자원을 읽고 쓰는 등의 컴퓨터가 수행하는 모든 연산에 해당된다.

예를 들어 어떠한 수에 1을 곱하는 x => x * 1과 같은 함수는 어떠한 값에 1번을 적용하던, 1000번을 적용하던 항상 x를 반환한다. 이런 연산을 멱등성이 보장된다.
그러나 1을 곱하는 함수가 아니라 1을 더하거나 빼는 함수라면 함수가 한번 호출될 때마다 인자로 주어진 값을 계속 증가시키거나 감소시킬 것이므로 항상 같은 값을 반환하지 않는다. 이런 연산은 멱등성을 보장하지 않는 예이다.

HTTP 메소드 또한 결국 어떤 자원을 쓰고 읽고 수정하고 지우는 CRUD의 의미를 가지기 때문에, 우리는 어떤 행위가 멱등성을 보장하고 어떤 행위가 멱등성을 보장하지 않는지 알고 있어야 어플리케이션이 예상하지 못한 방향으로 동작하는 것을 방지할 수 있다.

Method멱등성 보장

GET O
PUT O
DELETE O
POST O
PATCH O

우선 GET 메소드는 단지 리소스를 읽어 오는 행위를 의미하기에 아무리 여러번 수행해도 결과가 변경되지 않는다.
마찬가지로 요청에 담긴 리소스로 기존 리소스를 그대로 대체해버리는 PUT 메소드도 여러번 수행해도 요청에 담긴 리소스가 변하지 않는 이상 연산 결과가 동일하다.

즉, 어떤 리소스를 읽어오거나 대체하는 연산은 멱등성을 보장한다.
그렇다면 멱등성이 보장되지 않는 케이스는 뭐가 있을까?

POST 메소드의 경우 리소스를 새롭게 생성하는 행위이기 때문에 여러번 수행하게 되면 매번 새로운 리소스가 생성된 것이고, 연산을 수행한 결과가 매번 달라진다.
POST 메소드와 같이 멱등성을 보장하지 않는 동작은 한 번 수행될 때마다 어플리케이션의 상황이 전혀 다르게 변할 수도 있따.

이러한 HTTP 메소드의 멱등성에 대한 지식은 에러에 대한 정보가 별로 없는 상태에서 디버깅을 진행할 때도 활용될 수 있기 때문에 여러모로 알고 있는 편이 좋다.
똑같이 통신 후에 발생하는 에러라고 해도 GET을 여러 번 수행했을 때 발생하는 에러와 POST를 여러 번 수행했을 때 발생하는 에러는 전혀 다른 컨텍스트를 가지고 있을 수 있다는 것이다.

PATCH는 왜 멱등성이 보장되지 않는다는걸까?

위 테이블에 PATCH메소드는 POST 메소드와 동일하게 멱등성이 보장되지 않는 메소드로 표기되어 있다.
그러나 사실 PATCH 메소드는 구현 방법에 따라서 PUT 메소드처럼 멱등성이 보장될 수도 있고, 혹은 보장되지 않을 수도 있다.
PATCH 메소드는 PUT 메소드처럼 리소스를 대체하는 행위가 아니기 때문에 요청을 어떤 방식으로 사용하는지에 대한 제한이 딱히 없기 때문이다.
RFC 스펙 상의 PATCH 메소드는 단지 리소스의 일부를 수정한다는 의미만을 가질 뿐이다.

예를 들어, PATCH 메소드에 수정할 리소스의 일부분만 담아서 보내는 경우에는 당연히 멱등성이 보장된다.

// 기존 리소스
{
    id: 1,
    name: 'evan',
    age: 30,
}
PATCH users/1
{ age: 31 }
// 새로운 리소스
{
    id: 1,
    name: 'evan',
    age: 31, // 변경됨
}

PATCH 요청은 명확하게 age라는 필드를 31로 수정하는 행위만을 의미하므로 아무리 여러 번 수행해도 age는 늘 31이라는 값을 가지기 떄문이다.

그럼 언제 PATCH 메소드가 멱등성 보장이 안될 수도 있다는 것일까?
예를 들어

PATCH users/1
{
    $increase: 'age',
    value: 1,
}

이 요청의 $increase 필드의 값은 증가시키고 싶은 속성을 의미하고, value 필드의 값은 그 속성을 얼마나 증가시킬 것인지를 나타낸다.
이 경우 API가 호출될 때마다 에반의 나이는 1씩 증가하기 때문에 이 API는 멱등성을 보장하지 않는다.

이런식으로 PATCH 메소드를 사용하는 경우를 실제로 보지는 못했지만, 스펙 상 구현 방법에 대한 제약이 없기 떄문에 이런 식으로 사용한다고 해서 표준을 어기는 것은 아니라고 한다.
따라서 PATCH 메소드는 API를 어떻게 구현하냐에 따라서 멱등성을 보장할 수도 있고 아닐 수도 있는 것이다.

References

프론트엔드와 백엔드가 소통하는 엔드포인트, RESTful API