What is HTTP Content Negotiation?
Learn how HTTP content negotiation works — Accept headers, q values, and Vary — to serve the right format, language, or encoding.
Expected Interview Answer
HTTP content negotiation is the process by which a client and server agree on the best representation of a resource to return — such as its format, language, or encoding — using request headers like `Accept`, `Accept-Language`, and `Accept-Encoding` that state the client’s preferences.
A single URL, like `/users/42`, can represent the same underlying resource in multiple forms: JSON or XML, English or French, gzip-compressed or plain. Server-driven negotiation lets the client send `Accept: application/json` or `Accept-Language: fr-FR` with quality weights (`q` values) to indicate preference order, and the server picks the closest match and echoes it back in the response’s `Content-Type` and `Content-Language` headers. When the chosen representation depends on request headers, the server should also send a `Vary` header (e.g., `Vary: Accept-Encoding`) so caches know to store separate copies per header combination. Agent-driven negotiation is the alternative, where the server returns a list of options (via a 300 Multiple Choices response) and the client or user picks one, though this is rare in practice compared to server-driven negotiation.
- Lets one URL serve multiple formats/languages without duplicate endpoints
- Client states preferences via Accept-* headers with quality weights
- Vary header keeps caches correct across differing negotiated responses
- Reduces payload size via Accept-Encoding-driven compression negotiation
AI Mentor Explanation
Content negotiation is like a stadium’s commentary booth offering the same match in multiple language channels — a fan tunes their headset to their preferred language, and the booth streams that specific audio feed instead of forcing everyone to listen in one fixed language. If a fan’s first-choice language channel is unavailable, they fall back to their next preference automatically. The booth’s channel selector is the same mechanism as a server reading the `Accept-Language` header. This is exactly how content negotiation matches a client’s stated preference to an available representation.
Step-by-Step Explanation
Step 1
Client states preferences
Request sends `Accept`, `Accept-Language`, and/or `Accept-Encoding` headers, optionally with `q` quality weights.
Step 2
Server matches available representations
Server compares its supported formats/languages/encodings against the requested preferences.
Step 3
Best match is chosen
Server picks the highest-preference match it can actually serve, falling back if the top choice is unavailable.
Step 4
Response reflects the choice
Server returns `Content-Type`/`Content-Language` for the chosen representation and a `Vary` header for caching correctness.
What Interviewer Expects
- Names the relevant Accept-* request headers and their purpose
- Explains quality (`q`) values for ranking preferences
- Knows why `Vary` matters for caching negotiated responses
- Can distinguish server-driven vs agent-driven negotiation
Common Mistakes
- Forgetting the `Vary` header, causing caches to serve the wrong representation to different clients
- Confusing `Accept` (response format) with `Content-Type` (request body format)
- Assuming every server supports every requested format instead of falling back gracefully
- Not knowing `q` values express relative preference, not a guarantee
Best Answer (HR Friendly)
“Content negotiation is how a server figures out the best version of a page or resource to send back — like choosing between JSON and XML, or English and French — based on what the client says it prefers in its request headers. It lets one URL serve many different audiences without duplicating endpoints.”
Code Example
# Ask for JSON explicitly
curl -H "Accept: application/json" https://api.example.com/users/42
# Ask for a specific language, with fallback preference
curl -H "Accept-Language: fr-FR, en;q=0.8" https://example.com/page
# Ask for compressed responses
curl -H "Accept-Encoding: gzip" -I https://example.com/
# Server should respond with a matching Vary header, e.g.:
# Vary: Accept-Encoding, Accept-LanguageFollow-up Questions
- How do quality (`q`) values resolve conflicting preferences?
- Why does the `Vary` header matter for CDN and browser caching?
- What is the difference between server-driven and agent-driven negotiation?
- How would you design an API that supports both JSON and XML via content negotiation?
MCQ Practice
1. Which header lets a client state its preferred response format?
The `Accept` request header tells the server which media types the client prefers to receive.
2. Why is the `Vary` header important with content negotiation?
`Vary` tells caches to store separate entries per differing header value, preventing serving the wrong negotiated variant.
3. What do `q` values in an `Accept-Language` header represent?
`q` values rank a client’s preferences, letting the server pick the best available match.
Flash Cards
What is HTTP content negotiation? — The process of choosing a resource representation based on client Accept-* header preferences.
Key request headers involved? — `Accept`, `Accept-Language`, `Accept-Encoding`, each optionally with `q` weights.
Why does `Vary` matter? — It tells caches which headers affect the response so they store the correct negotiated variant.
Server-driven vs agent-driven? — Server-driven picks automatically; agent-driven returns options for the client/user to choose (rare, via 300 status).