Safe Methods

  • Definition: An HTTP method is designated as safe if its core semantic is strictly read-only. It does not alter, mutate, create, or destroy the state of a resource on the server.
  • Included Methods: GET, HEAD, OPTIONS, TRACE.
  • Key Architecture Implications:
    • Caching & Prefetching: Because safe methods guarantee no side effects, web browsers, CDNs, and proxy servers can aggressively cache responses, prefetch links, or retry timed-out requests automatically without risking business logic corruption or accidental data modification.
    • Side Note on Server-Side State: The specification notes that “safe” applies strictly to resource states. Servers are still permitted to modify internal meta-states—such as updating access logs, tracking analytics, or incrementing hit counters—without violating the safety guarantee.

Unsafe Methods

  • Definition: An HTTP method is unsafe if its execution changes the server’s state, modifies resources, triggers financial transactions, or mutates database records.
  • Included Methods: POST, PUT, PATCH, DELETE.
  • Key Architecture Implications:
    • No Blind Retries: Clients and intermediate proxies cannot automatically retry unsafe requests (like a dropped POST request) if a connection fails mid-transit, as it might inadvertently duplicate a transaction (e.g., charging a credit card twice).
    • Restricted Caching: Unsafe methods are generally uncacheable by default because every execution can change what the resource looks like or returns.

Retries

To safely retry an unsafe method (such as a POST request to place an order or charge a payment), you must transform it into an idempotent operation at the application layer. Since network failures and timeouts prevent a client from knowing whether a dropped request ever reached the server, blind retries would otherwise cause duplicate side effects (like charging a credit card twice).

The industry-standard architecture to handle this safely relies on Idempotency Keys.

1. The Idempotency Key Pattern

An idempotency key is a unique token (typically a UUID) generated by the client and sent as a custom request header (e.g., Idempotency-Key: uuid-v4).

  • Client Responsibility: The client generates one key per logical business operation, not per HTTP transport attempt. If a network timeout occurs, the client retries the exact same request using the same idempotency key.
  • Server Contract: The key tells the server: “This is a unique business intent. If you have already processed this key, do not execute the side effect again; just return the original response.”

2. Server-Side Execution Flow

To make an unsafe method safe to retry, implement the following server lifecycle:

  1. Receive Request & Check Cache/Database:
    • When an unsafe request arrives with an Idempotency-Key header, the server checks its key store (such as Redis or a dedicated database table).
    • If the key already exists and has a completed status, the server immediately returns the exact stored response (status code, headers, and body) without re-running the business logic.
  2. Atomic Reservation (Handling Concurrent Duplicates):
    • If the key does not exist, the server attempts to atomically insert it with a status of IN_PROGRESS (often using a database unique constraint or a distributed lock).
    • If another concurrent request sneaks in with the same key and wins the race, the second request fails fast—typically returning a 409 Conflict or a retry hint.
  3. Execute and Commit Atomically:
    • The server executes the business logic (e.g., processing a transaction).
    • The business state change and the saving of the final response (linked to the idempotency key) must be written within the same database transaction. This prevents a crash from stranding the system in an unrecorded state.
  4. Return Response:
    • The final response is delivered to the client. Future retries with that key will safely bypass the core logic and replay this stored response.

3. Essential Guardrails

  • Request Fingerprinting: To prevent clients from accidentally or maliciously reusing the same key for different payloads, hash the request body and verify that any retry matches the original request fingerprint. If a mismatch occurs, reject it with a 422 Unprocessable Entity.
  • Expiration (TTL): Do not store idempotency keys forever. Set an expiration window (typically 24 to 48 hours) matching your maximum expected client retry horizon.

Caching

HTTP Caching Architecture

Caching behavior in HTTP is directly bound to method semantics, determining how intermediaries, CDNs, and browsers store and invalidate responses.

1. Cacheability by Method Type

  • Safe Methods (GET, HEAD): Designed for cacheability by default. Because they produce no side effects, intermediate proxies and edge nodes can aggressively serve stored responses without re-contacting the origin server.
  • Unsafe Methods (POST, PUT, PATCH, DELETE): Uncacheable by default under standard HTTP specifications because they alter resource states. While a response to a POST or PUT can theoretically be cached if explicit freshness headers (such as Cache-Control: max-age=...) are provided, doing so requires extreme caution to avoid serving stale transaction receipts.

2. Cache Invalidation Mechanics

When an unsafe method modifies or deletes a resource (PUT, PATCH, DELETE), HTTP specifications mandate that intermediaries must invalidate any stored cached representations for that target URI.

  • Reverse Proxy Hooks: Edge caching layers (like Varnish, Cloudflare, or AWS CloudFront) use successful write responses to purge associated cache tags or keys, ensuring subsequent read requests fetch the fresh state.

3. Conditional Requests & Validation

To balance performance and data integrity, HTTP utilizes conditional headers for both reading and writing:

  • Read Validation (ETag / If-None-Match): For GET requests, servers return an entity tag. Subsequent requests send If-None-Match: "hash". If the resource is unchanged, the server responds with 304 Not Modified, bypassing the response body transfer.
  • Write Concurrency (If-Match): For PUT and PATCH requests, clients can enforce optimistic locking by sending If-Match: "hash". If another transaction modified the resource in the interim, the server rejects the request with a 412 Precondition Failed, preventing race conditions and silent data overwrites.

Verification Checklist

  • Verify CDN cache rules enforce Cache-Control: no-store or private on all mutation endpoints (POST, PUT, PATCH, DELETE).
  • Implement strong ETag generation algorithms on backend resource read endpoints to support 304 Not Modified optimizations.
  • Configure automated cache purge hooks triggered immediately after database transaction commits for write operations.

Official Reference

The definitive, authoritative specification for HTTP methods, semantics, safety, and idempotency is standardized by the Internet Engineering Task Force (IETF) in RFC 9110: HTTP Semantics.

  • Section 9.2.1: Defines Safe Methods.
  • Section 9.2.2: Defines Idempotent Methods.