Lesson 18 / 27
Content Negotiation and the Accept Header
Let clients state preferred formats or versions with q-values and respond accordingly.
The client states preferences
With content negotiation the client lists acceptable representations in the Accept header, each with an optional quality value q from 0 to 1 (default 1), and the server picks the best match it supports or answers 406 Not Acceptable (or falls back to a default). The same mechanism can select a version through a vendor media type such as application/vnd.example.v2+json. Always include a Vary: Accept header on responses that depend on it so caches store separate copies, and document what happens when no preference is sent.
Parsing Accept with q-values, run
I ran this plain-Python example. The highest-quality media type comes first: the v2 vendor type (q=0.9), then plain JSON (0.5), then the wildcard (0.1).
import hmac, hashlib, json, time, bisect
def parse_accept(h):
items = []
for part in h.split(","):
bits = part.strip().split(";"); q = 1.0
for b in bits[1:]:
if b.strip().startswith("q="): q = float(b.strip()[2:])
items.append((q, bits[0].strip()))
return [m for q, m in sorted(items, key=lambda x: -x[0])]
print(parse_accept("application/vnd.example.v2+json;q=0.9, application/json;q=0.5, */*;q=0.1"))
Output:
['application/vnd.example.v2+json', 'application/json', '*/*']
Set a safe default
If a client sends no version, serve a stable, documented default (often the oldest supported version) rather than the newest, so existing integrations do not change under them.
Quick check: Which header should be added when the response depends on Accept?
- Vary: Accept
- Content-Length: 0
- Retry-After
- Location
Answer
Vary: Accept — Vary tells caches the response differs by the Accept header, avoiding the wrong copy being served.