합동회사 코무라소프트
2장

HTTP 메서드 — 안전·멱등이라는 약속

GET·POST·PUT·DELETE·HEAD 를 「무엇을 하고 싶은가」로 구분하고, 안전(서버의 상태를 바꾸지 않음)과 멱등(몇 번을 해도 같음)이라는 약속으로 경계를 그어, 재시도 판단에 쓸 수 있게 한다.

「일단 전부 POST」로 만들고 있지 않은가

폼도 가져오기도 삭제도, 돌아가니까 전부 POST 로 만들어 버린다. 혹은 반대로, 전송 버튼을 다시 클릭해서 주문이 이중으로 등록되어 버렸는데 원인을 모른다 — 메서드의 구분은, 돌아가기만 하면 애매해도 통과해 버리는 만큼, 사고가 난 뒤에야 효과가 드러나는 지식입니다.

앞 장에서 읽은 대로, 리퀘스트 행의 맨 앞에 있는 메서드는 왕복 서신의 동사입니다. HTTP 에는 메서드가 여럿 있지만, 우선 이 5 가지를 구분해 쓸 수 있으면 충분합니다.

GET
「이것을 주세요」— 리소스의 취득. 페이지를 열고, 이미지를 읽고, API 에서 목록을 얻는다
HEAD
「GET 과 같은 답을, 본문 없이」— 크기나 갱신 일시 등 헤더만 확인하고 싶을 때
POST
「이것을 처리해 주세요」— 폼 전송, 신규 작성, 그 밖의 처리 의뢰. 효과는 실행할 때마다 쌓일 수 있다
PUT
「이 URL 의 내용을, 이 내용으로 해 주세요」— 받는 곳을 지정한 치환(덮어쓰기 저장)
DELETE
「이 URL 의 것을 지워 주세요」— 삭제 의뢰

예를 들어 PUT /users/42/profile 은 「42 번 사용자의 프로필을 이 내용으로 하라」, POST /orders 는 「이 주문 내용을 처리해 새 주문을 만들라」. 받는 곳이 정해져 있는 치환은 PUT, 새로 생겨나는 것이나 처리 의뢰는 POST — 이것이 기본 구분입니다.

연습 2-1 — 5 가지 동사를 구분해 쓴다

「무엇을 하고 싶은가」에서 적절한 메서드를 고르는 연습입니다.

Q1. 온라인 숍 https://shop.example.com 에서, 주문 폼에 입력한 내용을 전송해 새 주문을 만들 때, 가장 적절한 메서드는 어느 것입니까.

Q2. 거대한 동영상 파일에 대해, 다운로드는 하지 않고 크기나 갱신 일시만 알고 싶을 때, 가장 적절한 메서드는 어느 것입니까.

Q3. PUT 과 POST 의 차이에 대한 설명으로 가장 적절한 것은 어느 것입니까.

2 가지 약속 — 안전과 멱등

5 가지 동사를 암기하는 것보다 중요한 것이, 메서드에 묶여 있는 2 가지 약속입니다. 이 두 단어는 사양서에도 오류 조사에도 자주 나옵니다.

안전(safe) — 서버의 상태를 바꾸지 않는다
「읽기만 한다」는 약속. GET 과 HEAD 가 해당. 몇 번을 호출해도 서버의 데이터는 변하지 않는다
멱등(idempotent) — 몇 번을 해도 최종 상태가 같다
1 번 실행하든 10 번 실행하든, 서버의 최종 상태가 같다는 약속. GET·HEAD 에 더해, PUT 과 DELETE 도 해당

여기서 손을 움직여 확인해 봅시다. PUT /users/42/profile 로 「이름 = 고무라」로 치환하는 리퀘스트를 3 번 보내도, 최종 상태는 「이름 = 고무라」— 1 번일 때와 같습니다. DELETE /orders/7 을 2 번 보내도, 7 번 주문이 지워져 있다는 최종 상태는 같습니다(2 번째는 404 가 돌아올지도 모르지만, 멱등성이 보는 것은 서버 쪽의 최종 상태입니다). 한편 POST /orders 를 3 번 보내면 주문이 3 건 생긴다 — POST 는 멱등이 아닙니다.

관계를 정리하면, 안전하면 반드시 멱등입니다(아무것도 바꾸지 않으니, 몇 번을 해도 같음). 역은 성립하지 않고, PUT 과 DELETE 는 「바꾸지만, 몇 번을 해도 같다」— 멱등이지만 안전하지 않다는 중간 띠에 들어갑니다.

GET·HEAD·POST·PUT·DELETE 각 HTTP 메서드에 대해 안전한지·멱등한지·주요 용도를 대응시킨 표

5 가지 메서드를 안전·멱등의 2 축으로 늘어놓은 지도입니다. GET/HEAD 는 두 약속을 모두 지키고, PUT/DELETE 는 멱등만, POST 는 어느 약속도 하지 않습니다. 이 지도가 「재시도해도 되는가」의 판단표가 됩니다.

실무에서의 효과 — 갱신의 재시도는 멱등성을 확인하고 나서

이 2 가지 약속이 실무에서 가장 잘 듣는 곳은, 통신이 실패했을 때의 재전송(재시도) 판단입니다.

리퀘스트를 보내고 타임아웃되었을 때, 사실 2 가지 가능성이 있습니다. 「리퀘스트가 서버에 도착하지 않았다」인가, 「도착해서 처리도 끝났는데, 답장만 사라졌다」인가 — 클라이언트에서는 구별할 수 없습니다. 여기서 멱등성이 듣습니다.

멱등한 메서드(GET/HEAD/PUT/DELETE)
설령 처리가 끝나 있어도, 재전송해도 최종 상태는 변하지 않는다. 안심하고 재시도할 수 있다
멱등하지 않은 메서드(POST)
처리가 끝나 있었다면, 재전송은 이중 처리(주문 2 건·결제 2 번)가 된다. 무조건적인 재시도는 위험

그렇기 때문에 브라우저는 POST 의 결과 화면에서 새로 고침을 하면 「폼을 다시 제출하시겠습니까?」라고 일부러 확인해 옵니다(이 장면은 제 7 장의 케이스에서 다시 등장합니다). 또, 자동 재시도를 내장한 라이브러리의 다수가 기본값으로 GET 만 재전송하는 것도, 이 약속이 근거입니다. 「갱신의 재시도는, 그 메서드가 멱등인지 확인하고 나서」 — 손이 기억할 때까지 되뇌어 주세요.

연습 2-2 — 안전과 멱등의 경계

2 가지 약속을 정확하게 구별해 말하고, 실무의 「재시도해도 되는가」에 연결합니다.

Q4. 메서드가 「안전(safe)」하다는 것은 어떤 약속입니까.

Q5. 「멱등이지만 안전하지 않은」 메서드의 조합은 어느 것입니까.

Q6. 갱신 계열의 API 리퀘스트를 보냈는데, 응답이 돌아오지 않고 타임아웃되었습니다. 같은 리퀘스트를 다시 보내기 전에 확인해야 할 것으로 가장 적절한 것은 어느 것입니까.

이 장에서 가져갈 것

  • 메서드는 왕복 서신의 동사. 취득은 GET, 본문 없는 확인은 HEAD, 처리 의뢰·신규 작성은 POST, 받는 곳 지정 치환은 PUT, 삭제는 DELETE
  • 안전 = 서버의 상태를 바꾸지 않는다(GET/HEAD). 멱등 = 몇 번을 해도 최종 상태가 같다(GET/HEAD/PUT/DELETE). 안전하면 반드시 멱등
  • POST 는 안전하지도 멱등하지도 않다. 타임아웃 후의 무조건적인 재시도는 이중 처리의 위험이 있다
  • 갱신의 재시도는 멱등성을 확인하고 나서 — 이 한 문장이 실무에서의 효과

부탁을 읽는 법이 몸에 익었으니, 다음 장은 왕복 서신의 반대쪽 — 서버가 보내는 답장입니다. 3 자리 상태 코드를 백의 자리부터 순서대로 읽어냅니다.