Skip to content

Idempotency: honor Idempotency-Key header and apply it to deletes - #91

Merged
sklinkert merged 1 commit into
mainfrom
sklinkert/idempotency-security-metrics
Jul 21, 2026
Merged

Idempotency: honor Idempotency-Key header and apply it to deletes#91
sklinkert merged 1 commit into
mainfrom
sklinkert/idempotency-security-metrics

Conversation

@sklinkert

@sklinkert sklinkert commented Jul 21, 2026

Copy link
Copy Markdown
Owner

Context

The recently added race-safe idempotency layer (#86) is well-built and correctly placed at the application-service layer, but it had two gaps at the HTTP boundary:

  1. Deletes bypassed idempotency entirelyDeleteProductController/DeleteSellerController built their commands with only Id and never set IdempotencyKey, even though the command structs already had the field. An empty key short-circuits withIdempotency, so delete replays were never cached.
  2. The key travelled only in the JSON body (idempotency_key) rather than the conventional Idempotency-Key HTTP header — a notable smell for a reference repo people copy into production.

This PR closes both gaps. No new infrastructure — the existing withIdempotency wrapper, repository, table, and command fields are reused as-is.

Changes

  • New idempotencyKey helper (internal/interface/api/rest/idempotency.go) — prefers the Idempotency-Key header, falls back to the request body's idempotency_key field for backward compatibility (header wins when both are present).
  • All six mutating handlers (product/seller create, update, delete) now resolve the key via the helper. Deletes now carry a key into DeleteProductCommand/DeleteSellerCommand.
  • Unit tests for the helper (header precedence / body fallback / empty).
  • OpenAPI spec — reusable Idempotency-Key header parameter referenced from every write operation, plus an updated description.
  • README — documents that the header is preferred and that deletes are idempotent too.

Write endpoints previously took the idempotency key only from the JSON
body's optional idempotency_key field, and delete handlers never passed a
key at all — so deletes had no idempotency protection.

- Add an idempotencyKey helper that prefers the conventional
  Idempotency-Key HTTP header and falls back to the body field for
  backward compatibility (header wins when both are present).
- Resolve the key via the helper in all six mutating handlers, and plumb
  it into DeleteProductCommand/DeleteSellerCommand (fields already existed
  but were never populated).
- Document the header in the OpenAPI spec and README.

Fully backward compatible: existing body-key and no-key callers are
unchanged.
@sklinkert
sklinkert merged commit cd85d78 into main Jul 21, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant