# Caching and Conditional Requests (ETag) — API Design and Versioning

Source: https://www.geekswithgeeks.com/en/api-design/rel-conditional

> Use ETag and If-None-Match to avoid re-sending unchanged data and Cache-Control for caching.

## Ask "has it changed?"

An **ETag** is an opaque version tag for a representation (often a hash). The server sends `ETag: "abc"`; later the client repeats the request with `If-None-Match: "abc"`. If the resource has not changed, the server answers **`304 Not Modified`** with no body, saving bandwidth and time. The same tags give **optimistic concurrency** for writes: the client sends `If-Match: "abc"` with a `PUT`/`PATCH`, and the server returns `412 Precondition Failed` if someone else changed the resource first, preventing lost updates. `Cache-Control` (`max-age`, `private`, `no-store`) tells browsers and CDNs how long to reuse a response; mark responses containing personal data `private` or `no-store`.

## A 304 from the real API, run

I ran this against a small real HTTP API built with only the Python standard library (full code in the case study). The first `GET` returns the item and an `ETag`. Repeating it with that tag as `If-None-Match` returns `304` with no body (`None`).

```python
# uses srv, base and call() from the runnable demo in the case study
s, h, b = call("GET", "/v2/items/1"); tag = h["ETag"]; print(s, b, "has etag:", tag.startswith('"'))
s, h2, b2 = call("GET", "/v2/items/1", headers={"If-None-Match": tag}); print(s, b2)

```

Output:

```
200 {'id': 1, 'first_name': 'Asha', 'last_name': 'Rao', 'plan': 'pro'} has etag: True
304 None
```

## Use If-Match to prevent lost updates

Two people edit the same record: without `If-Match`, the second save silently overwrites the first. With it, the second gets a clear `412` and can reload and merge.

**Quiz:** What does `304 Not Modified` tell the client?

- [x] The cached copy is still valid; no body is sent
- [ ] The resource was deleted
- [ ] The request failed
- [ ] Credentials are wrong

*Answer:* The cached copy is still valid; no body is sent. A conditional GET with a matching ETag lets the server skip the body.
