동일한 연산을 여러 번 수행하더라도 서버의 최종 상태가 처음 한 번 수행했을 때와 동일하게 유지되는 성질을 의미합니다.
멱등성은 서버의 상태가 동일함을 의미하며, 매 요청마다 반환되는 HTTP 응답 코드나 결과 메시지까지 완전히 동일해야 함을 의미하는 것은 아닙니다.
ex ) DELETE 요청 시 첫 번째는 200 OK, 두 번째는 404 Not Found가 반환될 수 있지만, 리소스가 삭제된 서버의 최종 상태는 동일하므로 멱등합니다.
| HTTP 메서드 | 안전성 | 멱등성 | 설명 |
|---|---|---|---|
| GET / HEAD / OPTIONS | O | O | 서버의 상태를 변경하지 않고 단순히 조회하므로 안전하며 멱등함 |
| PUT | X | O | 리소스를 완전히 대체하므로 여러 번 수행해도 최종 상태는 동일함 |
| DELETE | X | O | 리소스를 삭제하므로 여러 번 수행해도 리소스가 삭제된 상태는 동일함 |
| POST | X | X | 호출할 때마다 새로운 리소스를 생성하거나 상태를 변경하므로 비멱등함 |
| PATCH | X | △ (기본 X) | RFC 스펙상 비멱등. 설계 방식(절댓값 지정 vs 상대값 증가)에 따라 멱등할 수도 있음 |
안전한 메서드 : 서버의 리소스를 전혀 변경하지 않는 읽기 전용 메서드입니다. ( GET, HEAD, OPTIONS )
안전성 vs 멱등성 : 안전한 메서드는 항상 멱등하지만, 멱등한 메서드가 반드시 안전한 것은 아닙니다. PUT과 DELETE는 서버 상태를 변경하므로 안전하지 않지만, 여러 번 호출해도 최종 상태가 같으므로 멱등합니다.
분산 시스템이나 네트워크 통신 환경에서는 타임아웃, 네트워크 끊김, 클라이언트의 중복 클릭 등으로 인해 동일한 요청이 여러 번 전송될 수 있습니다.
비멱등한 API ( ex. 결제 POST 요청) : 네트워크 타임아웃 발생 시 클라이언트가 재시도하면 중복 결제가 발생할 위험이 있습니다.
멱등한 API : 동일한 요청이 중복 전송되더라도 실제 비즈니스 로직(결제 처리)은 단 한 번만 실행되고, 이후 요청에는 이전에 처리된 결과를 반환하므로 안심하고 재시도할 수 있습니다.
본질적으로 멱등하지 않은 POST나 PATCH 요청을 멱등하게 만들기 위해 표준 요청 헤더인 Idempotency-Key를 활용합니다.
POST /v1/payments HTTP/1.1
Host: api.example.com
Idempotency-Key: 7b9b1e22-261d-44a3-a006-259160a2b53f
Content-Type: application/json
{
"amount": 10000,
"currency": "KRW"
}
처리 흐름
클라이언트 : UUID v4와 같이 충분히 무작위적이고 고유한 값을 Idempotency-Key 헤더에 담아 요청을 전송합니다.
서버 (키 조회 및 검증) :멱등성 키 저장소( Redis, DB )에서 해당 키를 조회합니다.
요청 핑거프린트 검증 : 동일한 멱등성 키로 들어왔으나 요청 본문이 이전 요청과 다르면 에러(422)를 반환합니다.
서버 (처리 분기):
409)를 반환합니다.여러 API에서 일관된 멱등성을 보장하기 위해 인터셉터나 미들웨어 형태로 컴포넌트화하여 재사용하는 것을 권장하며, 다음과 같은 HTTP 상태 코드로 예외를 응답합니다.
| 에러 코드 (Status) | 시나리오 및 원인 |
|---|---|
| 400 Bad Request | 멱등성이 필수인 API에 Idempotency-Key 헤더가 누락되었거나, 올바른 UUID 형식이 아닐 때 |
| 409 Conflict | 동일한 멱등성 키로 첫 번째 요청이 현재 처리 중인 상태에서 두 번째 요청이 연달아 들어왔을 때 (동시성 락) |
| 422 Unprocessable Entity | 기존에 사용했던 멱등성 키를 재사용했으나, 요청 본문(Payload)이나 파라미터가 첫 요청과 다를 때 |