Module 4: API Design & Contract Evolution: Worked Examples
Example 1: Make Retry Safe
Problem. A client times out after POST /payments; the server may have charged the card.
Wrong attempt. Retry blindly. A second successful request can create a second charge.
Correct reasoning. Require an idempotency key scoped to caller and operation. Persist the key, request fingerprint, state, and eventual response atomically with starting the business operation. An identical retry returns the recorded result; a reused key with a different payload is rejected.
Example 2: Evolve a Field Without Breaking Consumers
Changing fullName: string to {first,last} is not additive if clients compile against the old shape. Add the new structure while retaining the old field, define precedence, instrument usage, publish migration examples and dates, then remove only after the compatibility window and observed adoption satisfy policy.
Evidence. Consumer-driven contract tests and telemetry support the decision; version numbers alone do not.
Example 3: Design Pagination Under Concurrent Inserts
Offset pagination can duplicate or skip records when new rows arrive before the current offset. Use a stable sort such as (created_at DESC, id DESC) and an opaque cursor encoding the last tuple. Define cursor expiry, filter binding, and invalid-cursor errors.
Completion Standard
- Specify retry, timeout, and idempotency behavior for a mutating endpoint.
- Execute an additive-to-removal contract migration.
- Test pagination while inserts occur between page requests.