일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- JPQL
- ExceptionResolver
- enumSet
- 인프콘2023
- Test Doulbe
- Coputer Science
- Spring
- Service 계층 테스트
- modelmapper
- proxyFactory
- 테크쇼
- MySQL
- db
- RequestBody
- OS
- Server
- 소프티어
- Test code
- Junit 5
- FCM
- softeer
- Java
- mapstruct
- 공룡책
- ObjectMapper
- 일상
- backend
- Test
- 자바
- JPA
- Today
- Total
공부내용공유
Put vs Patch 뭐가 더 좋을까? (feat : patch는 왜 멱등 안 함) 본문
서론
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의 한 종류라 하면 멱등하지 않음이 이해가 된다.
- move를 통해 파일을 위치 a -> 위치 b로 옮기는 명령의 경우 2번 째 명령에서는 a위치에 파일이 없다는 오류가 발생할 것이다.
- 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이 아니면 업데이트 하는 로직을 작성해야한다.
- 도메인 메서드로 값을 바꿔주고 jpa들을 사용해 save
- 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번은 Patch, 2번은 Put이 맞다고 생각할 수 있다. 그러나 ui는 너무나도 자주 변하기에 ui에 따라 api를 결정하는 것은 잘못됐다고 생각한다, 결과론적으로는 나쁘지 않은 선택이 될 수 있지만 그렇게 하는 것 보다는 다른 것을 기준으로 컨벤션을 정하고 선택을 하는게 길게 봤을 때 이해하기 쉬운 엔드포인트, 유지보수 하기 좋은 코드를 만들 수 있다고 생각한다.
결론
대충 얘는 이렇게 생각하는구나 하고 이거 고민에 시간 쏟지말고 어느정도 기준에 따라 빠르게 정하고 비즈니스 로직이나 다른 중요한 부분에 시간을 투자하자가 내가 하고 싶은 말이었다.