HTTP 메서드의 속성은 크게 3가지로 안전(Safe), 멱등(Idempotent), 캐시 가능(Cacheable)이 있다. HTTP 메서드별로 가지는 속성이 다르기 때문에 어떤 HTTP 메서드로 요청을 했냐에 따라 설계나 로직, 요청 실패시 처리하는 방법 등이 달라질 수 있다. 웹 개발자라면 이에 대해 알아야 할 필요가 있기 때문에 이번 포스팅은 이를 정리해 보는 시간.
이번 포스팅에서는 HTTP 주요 메서드(GET, POST, PUT, PATCH, DELETE)에 대해 정리할 것이다.
안전 (Safe)
HTTP 메서드의 안전성이란 호출해도 리소스가 변경되지 않는 성질을 말한다. (RFC 문서)
GET메서드는 데이터 조회기능을 호출해도 리소스를 변경하거나 수정하지 않기 때문에 안전한 메서드이다.
그 외 POST, PUT, PATCH, DELETE 는 데이터에 변경이 일어나거나, 삭제되기 때문에 안전하지 않은 메서드이다.
트래픽이 몰려 GET 요청이 많아져 장애가 발생하면 안전하지 않다고 생각할 수 있지만 여기서 안전은
해당 리소스의 수정 및 삭제에 대한 여부, 즉 데이터의 일관성 유지에 대해 안전함을 의미하는 것이다.
멱등성 (Idempotent)
HTTP 메서드의 멱등이란 여러 번 동일한 요청을 보냈을 때, 서버에 미치는 영향이 동일한 경우를 의미한다. (RFC 문서)
위 문장만 볼 때, 안전과 같다고 생각할 수 있는데, 안전은 여러번 호출해도 리소스의 수정이 발생하지 않는다는 속성이고, 멱등은 리소스의 수정이 발생해도 여러번 요청을 한 것과 한번 요청을 한 것과 결과가 같다는 속성이다.
하나씩 차례로 알아보자.
GET 메서드의 멱등성 ( o )
같은 요청을 여러번 해도 같은 결과가 조회되므로 멱등을 만족한다. 하지만 만약에 GET 메서드를 사용함과 동시에 데이터를 추가하게끔 API를 설계한다면 HTTP 스펙에 부합하지 않게 된다. 예를들어, GET 메서드로 게시글을 조회함과 동시에 조회수를 증가시키도록 하는 경우이다.
1. GET /boards/1
2. Id가 1인 게시글 조회 및 조회수 데이터 증가
3. 요청 응답
HTTP 스펙에 부합하도록 즉, GET 메서드의 멱등에 맞게 API를 설계하려면 조회수 데이터를 증가시키는 부분은 PATCH 요청으로 따로 설계하는 것이 올바른 경우라고 할 수 있겠다.
그리고 첫 요청으로 데이터를 조회한 후 중간에 데이터가 수정되고 나서 다시 조회한 경우에 멱등을 만족하지 않다라고 생각할 수 있다. 사용자1과 사용자2가 있고 순서대로 각각 아래와 같은 행동을 했다고 가정해보자.
1. 사용자1 : GET username: kanghowoo , age: 30
2. 사용자2 : PUT username: kanghowoo , age: 50
3. 사용자1 : GET username: kanghowoo , age: 50 → (사용자2로 인해 age: 50 데이터가 조회됨)
위와 같은 경우를 생각하면 멱등을 만족하지 않다고 생각할 수 있지만, 멱등의 여부는 외부 요인으로 중간에 리소스가 변경되는 것은 고려하지 않는다.
POST 메서드의 멱등성 ( x )
POST 메서드는 서버에 데이터를 보내 새로운 자원을 생성하기 때문에 여러번 호출하면 계속해서 새로운 자원을 생성하게 된다. 온라인 카드 결제를 떠올려보면 요청을 여러번 할 경우, 결제가 중복으로 발생할 수 있다. 그렇기 떄문에 중복 요청에 대해 결제되지 않도록 설계해야 한다.
PUT 메서드의 멱등 ( o )
PUT 메서드는 대상 리소스 전체를 덮어씌우기 때문에 여러번 요청한 경우와 한번 요청한 경우, 서버에 미치는 영향은 같다. 추가로 알아둘 점은 PUT은 덮어씌울 데이터가 없는 경우는 데이터를 새로 생성하는데 덮어씌울 경우와 새로 생성하는 경우의 HTTP response code가 다르다. (다른 응답 코드를 받았다고 해서 멱등하지 않다는 것이 아니다. 서버에 미치는 영향은 같기 때문에!)
( 덮어씌운 경우는 정상처리이기 때문에 200 OK , 새로 생성한 경우는 201 Created )
PATCH 메서드의 멱등 ( x )
PATCH는 리소스의 부분을 수정하는 경우에 사용된다. (PUT은 전체)
PUT처럼 리소스의 부분만 덮어씌우기 때문에 여러번 요청한 경우와 한번 요청한 경우가 같다고 생각할 수 있다. 하지만, '수정'하는 요청이 데이터를 덮어씌우는 경우가 아니라 추가하는 경우가 있기 때문에 PATCH 메서드는 멱등을 만족하지 못한다.
DELETE 메서드의 멱등 ( o )
DELETE는 단순 삭제인데, 여러번 요청해도 서버에 미치는 영향은 같다. PUT메서드의 경우와 같이 응답 코드는 요청마다 다르게 올 수 있을 것이다. (정상인 경우 200 OK, 삭제할 데이터가 없는경우 NOT FOUND 404)
응답 코드가 달라 (결과가 달라) 멱등을 만족하지 않는 것이 아니라, 서버에 미치는 영향(리소스 삭제)이 동일하기 때문에 멱등을 만족한다.
하지만 API 설계시에 아래 예시와 같이 같은 리소스를 지정해 처리하는 요청이 아니라면, HTTP 스펙에 부합하지 않게 될 것이다.
DELETE /boards/last → (게시글 목록의 마지막 게시글 삭제)
이런 경우는 DELETE 요청을 여러번 보내면 매번 마지막 게시글이 삭제 되므로 매번 서버에 미치는 영향이 다르다. 그렇다면, 의도적으로 게시글 목록의 마지막 게시글 삭제를 하려면 어떻게 하는 것이 옳바르다고 할 수 있을까? 멱등성을 가지지 않는 POST 메서드를 사용해 설계하는 것이 HTTP 스펙에 부합하다고 할 수 있겠다.
POST /boards/last
캐시 가능 (Cacheable)
캐시 가능은 응답 결과 리소스를 캐시해서 사용할 수 있는가의 여부이다.
웹 브라우저 자체에 캐시 공간이 있다라는 것을 들어본 적이 있을 것이다. 처음 조회된 페이지 리소스를 이 캐시 공간에 저장해 이후의 요청에 대해서는 서버에서 받아오지 않고, 이 캐싱된 리소스를 이용해 더욱 빠르게 조회할 수 있게 된다.
HTTP 스펙상으로는 GET, POST, PATCH, 그리고 HEAD 메서드가 캐시가 가능하지만 실제로는 GET, HEAD만 사용된다고 한다. 우선 캐시는 키,밸류 형태로 이용이 가능한데 POST, PATCH의 경우, 웹 페이지 본문 데이터까지 키로 사용해야 하는 경우 구현이 쉽지 않고, 캐시를 이용하려면 원본 데이터가 변경되지 않아야 하는데, POST, PATCH 메서드는 데이터가 변경이 되는 메서드이기 때문에 캐시 데이터 불일치 문제가 생기게 된다.
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!