Skip to content

go.idempotency_key

Correctness Medium

Detects state-modifying HTTP endpoints without idempotency key handling.

Without idempotency keys:

  • Duplicate operations - Retries create duplicate records
  • Double charges - Payment retries charge multiple times
  • Data inconsistency - Same request processed multiple times
// ❌ Before (no idempotency)
func createOrder(w http.ResponseWriter, r *http.Request) {
order := parseOrder(r)
db.Create(&order) // Duplicate on retry!
}
// ✅ After (with idempotency key)
func createOrder(w http.ResponseWriter, r *http.Request) {
idempotencyKey := r.Header.Get("Idempotency-Key")
if idempotencyKey == "" {
http.Error(w, "Idempotency-Key required", 400)
return
}
// Check if already processed
if result, ok := cache.Get(idempotencyKey); ok {
json.NewEncoder(w).Encode(result)
return
}
order := parseOrder(r)
db.Create(&order)
cache.Set(idempotencyKey, order, 24*time.Hour)
json.NewEncoder(w).Encode(order)
}
  • POST/PUT handlers without idempotency key checks
  • Payment processing without idempotency
  • Order creation without duplicate protection

Unfault generates idempotency middleware:

func IdempotencyMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method == "POST" || r.Method == "PUT" {
key := r.Header.Get("Idempotency-Key")
// Check/store key...
}
next.ServeHTTP(w, r)
})
}