REST API Content Negotiation
One resource can appear in many formats. A product might travel as JSON for a mobile app, XML for an older partner system, or CSV for a spreadsheet. Content negotiation lets the client and the server agree on the best format for each request without changing the URL.
The Menu Language Example
A tourist enters a restaurant and asks for the menu in English. The waiter hands over the English menu if one exists, and offers the local language when no English copy is available. Content negotiation follows the same pattern. The client states its preferences, and the server picks the closest match.
Key Headers
| Header | Sent By | Meaning |
|---|---|---|
| Accept | Client | Formats the client can read |
| Content-Type | Both | Format of the message body |
| Accept-Language | Client | Preferred human language |
| Accept-Encoding | Client | Compression formats it supports |
| Vary | Server | Tells caches which headers changed the response |
The Negotiation Flow
Client Server │ GET /products/12 │ │ Accept: application/xml │ │ ──────────────────────────────────────→ │ │ │ checks supported formats │ 200 OK │ │ Content-Type: application/xml │ │ ←────────────────────────────────────── │ │ │ │ GET /products/12 │ │ Accept: application/yaml │ │ ──────────────────────────────────────→ │ │ 406 Not Acceptable │ │ ←────────────────────────────────────── │
Accept Header and Quality Values
A client can list several formats and rank them with q values from 0 to 1. A higher number means a stronger preference.
Accept: application/json;q=1.0, application/xml;q=0.5, */*;q=0.1
The server reads this line and returns JSON when it can. XML comes next in line, and any other format serves as a last resort.
Content-Type on Requests
Content-Type describes the body a client sends. A POST with a JSON body carries Content-Type: application/json. The server returns 415 Unsupported Media Type when it cannot read the declared format.
Status Codes for Negotiation
- 406 Not Acceptable: the server cannot produce any format the client accepts.
- 415 Unsupported Media Type: the server cannot read the format of the request body.
Language and Compression
Accept-Language: hi, en;q=0.7 asks for Hindi first and English second. Accept-Encoding: gzip, br allows compressed responses. Compression often cuts JSON payloads by more than half, which speeds up mobile apps on weak connections.
Vendor Media Types
Some teams define custom media types to describe a specific version or shape of a resource.
Accept: application/vnd.bookstore.v2+json
This approach keeps URLs stable and moves version details into the header.
A Bookstore Example
A bookstore API serves one book at /books/5. A mobile app requests JSON because it parses JSON quickly. An accounting system requests CSV because it imports rows directly into a ledger. A legacy partner requests XML because its software expects that format. All three clients call the same URL and receive the same book data in the format they asked for.
┌── Accept: application/json ──→ { "id": 5, "title": "Atlas" }
/books/5 ─────┼── Accept: text/csv ──────────→ id,title
│ 5,Atlas
└── Accept: application/xml ───→ <book><id>5</id></book>
The server code keeps one internal model of the book and converts it into the requested format at the last step. This design keeps business logic in one place and limits format work to a thin layer.
Best Practices
- Default to JSON when the client sends no Accept header.
- Support a small set of formats and support them well.
- Send the Vary header whenever the response depends on a request header.
- Return a clear error body with 406 and 415 responses, listing the supported formats.
Common Mistakes
Ignoring the Accept Header
Some servers always return JSON. Clients that ask for XML receive the wrong format and fail to parse it.
Format Switching by File Extension Only
URLs like /products/12.xml work for simple cases. Headers keep one URL for one resource, which fits REST principles more closely.
Forgetting Vary
A cache without Vary may store the JSON version and serve it to a client that asked for XML.
