Be My Story의 동화 생성/수정/저장 로직은 다음과 같다.
동화 수정 요청에서 api 설계를 PATCH로 할지, PUT으로 할지 고민되었다.
그래서 HTTP RFC(Request For Comments)를 찾아보았다.
먼저 PUT부터 살펴보자.
The PUT method requests that the enclosed entity be stored under the supplied Request-URI. If the Request-URI refers to an already existing resource, the enclosed entity SHOULD be considered as a modified version of the one residing on the origin server. If the Request-URI does not point to an existing resource, and that URI is capable of being defined as a new resource by the requesting user agent, the origin server can create the resource with that URI.
요약하면
그렇다면 PATCH는?
The PATCH method requests that a set of changes described in the request entity be applied to the resource identified by the Request- URI. The set of changes is represented in a format called a "patch document" identified by a media type. If the Request-URI does not point to an existing resource, the server MAY create a new resource, depending on the patch document type (whether it can logically modify a null resource) and permissions, etc.
PATCH는 변화를 묘사한 request라고 한다.
PUT과 PATCH의 설명에서 가장 큰 차이점은 무엇일까?
PUT은 entity라고 표현하는 반면, PATCH는 a set of changes라고 표현한다는 것이다.
친절하게도 document에서는 PUT과 PATCH의 차이점을 설명한다.
The difference between the PUT and PATCH requests is reflected in the way the server processes the enclosed entity to modify the resource identified by the Request-URI. In a PUT request, the enclosed entity is considered to be a modified version of the resource stored on the origin server, and the client is requesting that the stored version be replaced. With PATCH, however, the enclosed entity contains a set of instructions describing how a resource currently residing on the origin server should be modified to produce a new version. The PATCH method affects the resource identified by the Request-URI, and it also MAY have side effects on other resources; i.e., new resources may be created, or existing ones modified, by the application of a PATCH.
가장 큰 차이점: server가 Request-URI에 의해 식별된 resource를 수정하기 위해 entity를 처리하는 방법
PUT | PATCH |
- enclosed entity는 server에 있는 resource의 수정된 버전 - 원래 resource가 클라이언트가 요청한 resource로 replace되어야 함. |
- server에 이미 존재하는 resource가 어떻게 수정되어야 하는지 표현하고 있음. |
PUT은 replace(대체)를 하는 것이기 때문에 resource가 완전한 상태여야 한다.
Be My Story에 적용해보자
동화책 entity를 간단하게 표현해보았다.
@Entity
public class Book {
private Long bookId; //db에 저장되는 id
private String title; //동화책 제목
private String genre; //동화책 장르
private String date; //동화책 날짜
}
PUT으로 동화책 수정 요청이 온다면 이런 모습일 것이다.
{
"bookId": 34,
"title": "백설공주",
"genre": "공주",
"date": "2023-09-22"
}
Book의 모든 필드가 포함되어 있다.
PATCH의 동화책 수정 요청은 다음과 같을 것이다.
{
"title": "백설공주",
"date": "2023-09-22"
}
이와 같이 수정이 필요한 부분만 담아서 보낸다.
결론
그래서 둘 중 뭘 쓸까?
나는 PUT Method로 구현하기로 결정했다.
이유는 다음과 같다.
1. PATCH의 경우 부분 수정할 데이터만 보내기 때문에 그에 따른 DTO를 생성해야 한다. Book 엔티티의 경우 변경할 수 있는 필드가 title, genre, date라고 한다면, 벌써 7가지의 경우의 수가 발생한다. Be My Story의 실제 Book 엔티티는 13개의 필드를 가지고 있어(모두 변경할 수 있는 건 아니지만) 경우의 수가 매우 늘어난다.
2. PATCH가 안전한 방법이 아니다.
RFC문서로 돌아가보자.
PATCH is neither safe nor idempotent as defined by [RFC2616], Section 9.1. A PATCH request can be issued in such a way as to be idempotent, which also helps prevent bad outcomes from collisions between two PATCH requests on the same resource in a similar time frame. Collisions from multiple PATCH requests may be more dangerous than PUT collisions because some patch formats need to operate from a known base-point or else they will corrupt the resource. Clients using this kind of patch application SHOULD use a conditional request such that the request will fail if the resource has been updated since the client last accessed the resource. For example, the client can use a strong ETag [RFC2616] in an If-Match header on the PATCH request.
정리하자면, 두 PATCH request가 비슷한 시간에 같은 resource에 오면, collision이 발생할 수 있다. 이것은 PUT collison보다 더 위험하다. 이는 PATCH가 안전하지 않은 이유 앞부분만 가져온 것이고, 더 많은 내용이 있다.
이런 안전상 이슈가 있음에도 PATCH를 쓰는 이유가 궁금해졌다.
PUT보다 간편해서일까?
나중에 찾아봐야겠다.
'캡스톤프로젝트' 카테고리의 다른 글
스프링부트로 팔로우/팔로잉 기능을 구현해보자 (4) | 2023.11.13 |
---|---|
[Spring/JPA] Slice를 사용한 무한 페이지네이션 (0) | 2023.09.29 |
[Nginx, Amazon Linux] Certbot을 이용한 https 인증받기 (0) | 2023.09.13 |
졸업프로젝트, 태초마을로 돌아가다 (0) | 2023.09.02 |
[SpringBoot] 팔로워, 팔로잉 기능 구현하기 2 (0) | 2023.08.30 |