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.