공부내용공유

Put vs Patch 뭐가 더 좋을까? (feat : patch는 왜 멱등 안 함) 본문

카테고리 없음

Put vs Patch 뭐가 더 좋을까? (feat : patch는 왜 멱등 안 함)

forfun 2024. 10. 26. 16:31

서론


 

Put vs Patch 검색하면 알 수 있듯이 여러 사람들이 어떤 차이가 있는지, 어떤 상황에 무엇을 사용해야 하는지 헷갈려하는 사안이다.

 

 

나도 처음 개발을 할 때는 어떤걸 사용해야 하는지 감이 잘 안왔는데 지금까지 개발을 하면서 느꼈던 선택의 기준, 고민할 점에 대해 간단히 정리할 예정이다. 

 

 

본론


이 글의 목차는

  • put, patch 차이
  • 어떤게 좋을까
  • 이렇게는 하지 말자.

로 구성될 예정이다.

 

 

Put,  Patch 차이

 

이 둘의 차이점은 너무나도 많은 블로그 글들, 커뮤니티 글들에 자세히 나와있다, 그래도 이 글의 분량을 위해 간단히 설명하자면

  • Put은 자원의 전체를, Patch는 자원의 일부를 업데이트 한다. (제일 직관적인 차이)
  • Put은 멱등하고 Patch는 멱등하지 않을 수 있다. (? 사실 대부분 개발에서는 멱등성을 지키게 사용하는 경우가 많아 잘 와닿지 않는다.)

 

자원의 부분 업데이트

 

이 부분이야 다들 잘 알고있을 것이다.

//요청 전  리소스 상태
{
  "id": 1,
  "name": "John Doe",
  "age": 30,
  "email": "john@example.com",
  "address": "123 Main St"
}

//put 요청 , 요청 후 
{
  "name": "New Name",
  "age": 28
}
{
  "name": "New Name",
  "age": 28
}

//patch 요청, 요청 후
{
  "name": "New Name",
  "age": 28
}
{
  "id": 1,
  "name": "New Name",
  "age": 28,
  "email": "john@example.com",
  "address": "123 Main St"
} 

 

이렇게 Put은 요청을 보낼 때 기존 값은 그대로 변하는 값은 새로운 값을 넣어서 요청을 보내야 하기에 기존 리소스의 값을 모두 알고 있어야 한다. 반면에 Patch는 변경할 값만 요청에 넣으면 되기에 해당 값만 알아도 된다.

 

 

멱등성...

뭐 Put이 멱등하다는건 납득이 간다. 요청을 했을 때 해당 자원이 없는 경우 요청받은 값을 기반으로 리소스를 만들고 있으면 해당 리소스를 요청 받은 값으로 대체하기에 멱등할 수 밖에 없다.

 

 

근데 Patch는 왜? Patch도 위 예시에서는 User의 이메일 변경 요청을 계속 날리면 변화가 없으니까 멱등한거 아닌가? 검색을 해보 JSON patch 라는 개념이 등장한다.

 

 

RFC 6092 문서에서 나온 Json Patch의 예시를 보면

PATCH /my/data HTTP/1.1
   Host: example.org
   Content-Length: 326
   Content-Type: application/json-patch+json
   If-Match: "abc123"

   [
     { "op": "test", "path": "/a/b/c", "value": "foo" },
     { "op": "remove", "path": "/a/b/c" },
     { "op": "add", "path": "/a/b/c", "value": [ "foo", "bar" ] },
     { "op": "replace", "path": "/a/b/c", "value": 42 },
     { "op": "move", "from": "/a/b/c", "path": "/a/b/d" },
     { "op": "copy", "from": "/a/b/d", "path": "/a/b/e" }
   ]

 

이런식으로 되어 있다. 이러한 json 요청들이 patch의 한 종류라 하면 멱등하지 않음이 이해가 된다.

  1. move를 통해 파일을 위치 a -> 위치 b로 옮기는 명령의 경우 2번 째 명령에서는 a위치에 파일이 없다는 오류가 발생할 것이다.
  2. add로 특정 리스트에 리소스를 추가하는 명령의 경우 여러번 실행하면 그만큼 계속 리소스가 쌓일 것이다.

근데 적어도 우리가 접하는 일반적인 개발에서의 patch와는 많이 다르다. 이건 걍 그렇구나 정도로만 알아두고 put vs patch 를 구분할 때생각할 점을 다음 챕터에서 알아보자.

 

어떤게 좋을까?

나도 개발을 하면서 뭐 엄청 확고한 기준이 생긴건 아니지만 일단 내가 느낀 차이를 Patch의 장단점을 얘기하면서 정리하겠다.

 

 

당연한 장점이지만 Put은 해당 리소스의 모든 값들을 요청으로 넘겨야 한다. 그 리소스 중에 사진, 동영상, 파일등과 같이 크기가 큰 데이터 필드가 있다면? (물론 효율성을 위해 그걸 다 같이 보관하진 않겠지만 예시를 위해) 굉장히 비효율적이 된다.

 

 

그럴때는 Put이 아닌 Patch를 통해 업데이트할 필드만 받아서 네트워크 요청의 크기를 최소화 할 수 있다. 그러면 단점은 무엇일까? 나는 개인적으로는 Patch를 구현하는데 번거로움이라고 생각한다. 예를 간단히 들어보면

 

public class UserSetting {
    private final long id;
    private final boolean useEmail;
    private final boolean useSms;
    private final boolean useVipService;
    private final booelan useAuthService;
    private final String authKey;
}

예시 생각하기가 어려워서 일단 이렇게만 했는데 이 모든 값들이 사용자가 수정이 가능하고 이에 대한 엔드 포인트를 만들자고 해보자.

 

patch의 경우 결국 req에 모든 필드에 대해 nullable하게 받고 null이면 기존 값, null이 아니면 업데이트 하는 로직을 작성해야한다.

  1. 도메인 메서드로 값을 바꿔주고 jpa들을 사용해 save
  2. QueryDsl을 사용해 null 값 빼고 업데이트하게 변경

등등 사용하는 기술, 취향에 맞게 코드 작성이 가능할 것이다.

 

 

자 근데 이러한 필드가 20개가 된다고 해보자. (설계를 다시 해야한다라고 생각하지 말고 걍 그렇다고 하자) 어떤 방식으로 구현을 하든 코드가 제법 보기 싫을 것이다.

 

 

그리고 각 설정이 모두 boolean 과 같은 크기가 작은 값들이고 각 필드들이 진짜 묶일만한 값이다 하면 Put을 통해 구현의 지저분함을 크게 줄일 수 있지 않나 싶다. (Put을 사용한다고 해서 프론트에서도 추가 공수가 생기는 것도 딱히 없으면)

 

 

그리고 만약 a라는 필드가 b라는 필드에 영향을 받는다고 해보자, 예를 들면

level : 2 [1,2,3]
bagSize = 10 [5,10,30]

 

 

이런식으로 레벨 선택에 따라 가방 사이즈가 영향을 받을 경우 각 레벨에 맞게 가방 사이즈를 제한하는 도메인 로직이 들어가야 할 것이다.
이렇게 서로 영향을 주는 필드들이 있을 경우에는 그 필드끼리 묶어서 Put으로 받는게 좋지 않나? 라고 생각한다.

 

 

클라이언트에서도 해당 필드들을 묶어서 방어 로직 작성 및 사용자에게 해당 사항을 알려주고 백엔드도 요청을 받아서 검증을 하는 식으로 말이다. (Patch로도 구현이 가능하지만 Put으로 만들고 엔드포인트 단위로 연관이 깊은 리소스끼리 분리하는게 좀 더 명확하지 않을까? 라는 생각이다. 반박 환영)

 

 

이렇게는 하지 말자

그래서 결론은 크기가 정말 큰 필드를 같이 보내야 하는 경우가 아니면 팀 컨벤션, 상황 취향에 맞춰서 적절히 정하고 나중에 필요하면 변경을 해도 괜찮지 않나 라고 생각한다.

 

 

다만 주의해야 할 점이 있다면 ui에 의존적으로 정하지는 않았으면 좋겠다. 이건 비단 Put vs Patch 뿐만 아니라 api를 만들 때도
적용되는 얘기이다. Ui에 의존적으로 api를 만들지 말자.

 

 

간단한 예시를 들자면 수정하는 화면을 생각해보자. 대표적으로는

  1. 토글 형식처럼 버튼 누르면 실시간으로 변경되는 경우
  2. 게시글 처럼 모든 칸들 채우고 한번에 수정! 누르는 경우

 

단순히 생각하면 1번은 Patch, 2번은 Put이 맞다고 생각할 수 있다. 그러나 ui는 너무나도 자주 변하기에 ui에 따라 api를 결정하는 것은 잘못됐다고 생각한다, 결과론적으로는 나쁘지 않은 선택이 될 수 있지만 그렇게 하는 것 보다는 다른 것을 기준으로 컨벤션을 정하고 선택을 하는게 길게 봤을 때 이해하기 쉬운 엔드포인트, 유지보수 하기 좋은 코드를 만들 수 있다고 생각한다.

 

 

결론


대충 얘는 이렇게 생각하는구나 하고 이거 고민에 시간 쏟지말고 어느정도 기준에 따라 빠르게 정하고 비즈니스 로직이나 다른 중요한 부분에 시간을 투자하자가 내가 하고 싶은 말이었다.