
REST API 멱등성은 면접용 용어처럼 보이지만, 실제로는 장애를 막는 설계 기준입니다. 네트워크 오류로 같은 요청이 다시 보내질 때 서버가 어떻게 반응해야 하는지와 연결됩니다.
핵심은 같은 요청을 여러 번 처리해도 최종 서버 상태가 의도와 다르게 변하지 않게 하는 것입니다. POST, PUT, PATCH는 이 지점에서 다르게 봐야 합니다.
REST API 멱등성 빠른 기준

멱등성은 같은 요청을 반복했을 때의 이야기다
HTTP Semantics 표준인 RFC 9110은 멱등 메서드를 같은 요청을 여러 번 수행해도 한 번 수행한 것과 의도된 효과가 같은 메서드로 설명합니다.
중요한 표현은 ‘의도된 효과’입니다. 로그가 여러 줄 남거나 응답 시간이 달라지는 것은 있을 수 있지만, 주문이 두 번 생성되거나 결제가 두 번 발생하면 멱등하지 않은 설계입니다.
PUT은 왜 멱등하다고 말할까
PUT은 보통 특정 리소스의 전체 상태를 지정한 값으로 교체한다는 의미로 사용합니다. 같은 사용자 프로필을 같은 값으로 PUT하면 한 번 보내든 세 번 보내든 최종 상태는 같습니다.
PUT /users/42/profile
Content-Type: application/json
{
"nickname": "bscode",
"bio": "Android developer"
}그래서 PUT은 재시도에 비교적 강한 메서드로 설계하기 쉽습니다. 단, 서버가 PUT을 받을 때마다 새 리소스를 만들거나 카운터를 증가시키면 그 API는 이름과 달리 멱등하지 않게 됩니다.
POST는 왜 조심해야 할까
POST는 보통 새 리소스 생성이나 명령 실행에 쓰입니다. POST /orders를 두 번 보내면 주문이 두 개 만들어질 수 있습니다. 결제 API라면 더 위험합니다.
네트워크 오류가 나면 클라이언트는 응답을 못 받았을 뿐 서버 처리는 성공했을 수 있습니다. 이때 같은 POST를 그대로 재시도하면 중복 생성 문제가 생깁니다.
idempotency key는 요청을 식별하는 장치다
중복 요청을 막기 위해 많이 쓰는 방식이 idempotency key입니다. 클라이언트가 같은 작업에 같은 키를 붙여 보내면, 서버는 이미 처리한 키인지 확인하고 같은 결과를 반환하거나 중복 처리를 막을 수 있습니다.
POST /payments
Idempotency-Key: order-20260712-0001
Content-Type: application/json
{
"orderId": "20260712-0001",
"amount": 30000
}Stripe의 idempotent requests 문서도 API 요청 재시도에서 같은 키를 사용해 중복 처리를 피하는 방식을 설명합니다. 결제처럼 한 번만 처리되어야 하는 작업에서는 이 개념이 특히 중요합니다.
PATCH는 항상 멱등하지도, 항상 비멱등하지도 않다
PATCH는 부분 변경을 뜻하지만, 실제 멱등성은 요청 내용에 따라 달라집니다. 닉네임을 특정 값으로 바꾸는 PATCH는 반복해도 최종 상태가 같을 수 있습니다. 반면 포인트를 100 증가시키는 PATCH는 반복할 때마다 결과가 달라집니다.
- PATCH /users/42 { nickname: “bscode” } 는 멱등하게 설계할 수 있다.
- PATCH /wallets/42 { increment: 100 } 는 반복될 때 결과가 달라질 수 있다.
- 메서드 이름보다 실제 상태 변화 규칙을 봐야 한다.
서버 쪽 구현 감각: key를 어디에 저장할까
idempotency key는 헤더에 받는 것만으로 끝나지 않습니다. 서버가 그 키로 이미 처리한 요청인지 확인할 수 있어야 합니다. 보통은 사용자, 요청 목적, key, 처리 상태, 응답 요약을 함께 저장합니다.
handlePayment(request):
key = request.header["Idempotency-Key"]
userId = request.user.id
existing = idempotencyStore.find(userId, key)
if existing.completed:
return existing.savedResponse
result = paymentService.charge(request.body)
idempotencyStore.save(userId, key, result.response)
return result.response여기서 key만 저장하면 부족할 수 있습니다. 같은 key로 다른 금액을 보내는 요청을 막아야 하고, 처리 중인 요청이 동시에 들어왔을 때 race condition도 고려해야 합니다.
재시도 정책과 멱등성은 함께 설계한다
- 클라이언트가 언제 재시도할지 정한다.
- 서버가 같은 요청을 어떻게 식별할지 정한다.
- 처리 중인 요청과 완료된 요청을 구분한다.
- 같은 key에 다른 payload가 오면 오류로 볼지 정책을 정한다.
- idempotency key 보관 기간을 정한다.
POST를 멱등하게 만들 수 있는 경우
POST가 항상 비멱등이어야 하는 것은 아닙니다. 새 결제 요청처럼 생성형 작업이어도, 서버가 idempotency key를 기준으로 같은 작업을 한 번만 처리하게 만들면 클라이언트 입장에서는 안전하게 재시도할 수 있습니다.
즉 메서드 이름만 보고 끝내면 부족합니다. 실제 서버 동작, 저장소 제약 조건, 중복 요청 처리 정책까지 합쳐서 멱등성을 판단해야 합니다.
정리
REST API 멱등성은 POST, PUT, PATCH 정의를 외우는 문제가 아닙니다. 실패 후 재시도했을 때 서버 상태가 어떻게 되는지 묻는 설계 문제입니다. 특히 결제, 주문, 예약, 포인트처럼 중복 처리가 치명적인 API는 idempotency key와 요청 기록 전략을 함께 설계해야 합니다.
API 경계를 정할 때는 리소스 이름뿐 아니라 도메인 경계도 함께 봐야 합니다. 이 관점은 DDD의 Bounded Context 글에서 다룬 ‘같은 단어가 다른 의미를 가질 수 있다’는 문제와도 연결됩니다.