# pytest API testing practice: verify ETag cache revalidation

A response without JSON can still be correct. Read the standings once, preserve its ETag, and send that value back in If-None-Match using the same isolated sandbox.

## Before you start

- Python with pytest and requests installed: python -m pip install pytest requests.
- Save the code as test_cache.py and run python -m pytest test_cache.py.
- Outbound HTTPS access to funapi.dev.

## Compare the original and conditional responses

Use one session and one sandbox identifier for the pair of GET requests. Match the returned ETag exactly, including quotes and its weak-validator prefix.

```python
from uuid import uuid4
import requests

def test_standings_etag_revalidation():
    url = "https://funapi.dev/api/football/v1/standings"
    with requests.Session() as session:
        session.headers.update({"X-Sandbox-ID": str(uuid4())})
        first = session.get(url, timeout=15)
        assert first.status_code == 200
        assert len(first.json()["data"]) > 0
        etag = first.headers.get("ETag")
        assert etag

        cached = session.get(url, headers={"If-None-Match": etag}, timeout=15)
        assert cached.status_code == 304
        assert cached.content == b""
        assert cached.headers["ETag"] == etag
```

## Explain what was saved

The first request transfers the representation. The conditional request revalidates it and receives 304 with no representation body. This exercise checks protocol behavior; it does not claim a measured performance improvement.


## Expected result

One passing test that observes 200 followed by 304, an unchanged ETag and an empty second response body.

## Common pitfalls

- Do not call cached.json(): a 304 has no JSON response body.
- Do not strip quotation marks from an ETag.
- Do not compare standings to live sports results; the dataset is training data.
