Skip to content

Restful Content Negotiation

DodaTech 2 min read

title: "RESTful Content Negotiation — JSON, XML, and Custom Media Types" description: "RESTful content negotiation lets clients specify desired response format via Accept and Content-Type headers, supporting JSON, XML, and vendor-specific media types." date: 2026-06-28 lastmod: 2026-06-28 weight: 14 tags: [apis, restful] }

RESTful content negotiation allows clients to request specific response formats through HTTP Accept and Content-Type headers, supporting multiple representations of the same resource.

What You'll Learn

  • Content negotiation via Accept header
  • Supporting multiple formats
  • Vendor-specific media types

Why It Matters

Content negotiation decouples resource identity from representation. The same URI serves JSON, XML, or custom formats based on client preferences.

Code Examples

from flask import request, jsonify, make_response
import dicttoxml

@app.route('/users')
def get_users():
    # Determine response format
    accept = request.headers.get('Accept', 'application/json')

    users_data = [u.to_dict() for u in db.get_users()]

    if 'application/xml' in accept or 'text/xml' in accept:
        xml_response = dicttoxml.dicttoxml(users_data, custom_root='users')
        response = make_response(xml_response)
        response.headers['Content-Type'] = 'application/xml'
        return response

    # Default: JSON
    response = jsonify(users_data)
    response.headers['Content-Type'] = 'application/json'
    return response

# Vendor-specific media types
@app.route('/users/<int:id>')
def get_user(id):
    accept = request.headers.get('Accept', 'application/json')

    user = db.get_user(id)
    user_data = user.to_dict()

    if 'application/vnd.api.v2+json' in accept:
        # v2 format with additional fields
        user_data['full_name'] = f"{user.first_name} {user.last_name}"
        user_data['email'] = user.email
        content_type = 'application/vnd.api.v2+json'
    else:
        # v1 format
        user_data['name'] = user.first_name
        content_type = 'application/vnd.api.v1+json'

    response = jsonify(user_data)
    response.headers['Content-Type'] = f'{content_type}; charset=utf-8'
    response.headers['Vary'] = 'Accept'
    return response
// Express content negotiation
app.get('/api/users', (req, res) => {
  const users = db.getUsers();

  res.format({
    'application/json': () => {
      res.json(users);
    },
    'application/xml': () => {
      res.type('application/xml');
      res.send(xmlBuilder.buildObject({ users }));
    },
    'default': () => {
      res.status(406).json({ error: 'Not acceptable' });
    }
  });
});

Common Mistakes

1. Ignoring Accept Header

Returning JSON when client asked for XML.

2. Not Returning 406

Return 406 Not Acceptable when format is unsupported.

3. No Vary: Accept Header

Caches serve wrong format without Vary header.

4. File Extensions Instead of Negotiation

/users.json and /users.xml duplicate endpoints.

5. Case-Sensitive Format Comparison

Media types are case-insensitive. Compare lowercase.

Practice Questions

  1. What header does the client send to request a format?
  2. What status code for unsupported media types?
  3. Why use Vary: Accept?
  4. What is a vendor media type?
  5. How do you support multiple formats in one endpoint?

Answers:

  1. Accept header.
  2. 406 Not Acceptable.
  3. So caches store separate copies per Accept header value.
  4. A custom media type like application/vnd.company.v1+json.
  5. Parse Accept header and return the best matching format.

Challenge: Add XML support to your JSON API using content negotiation. Ensure Vary: Accept is set for proper caching.

FAQ

Should I support both JSON and XML?

: JSON is sufficient for most APIs. Add XML only if clients need it.

What is the q parameter in Accept header?

: Quality value (0-1) indicating preference priority.

Can I use content negotiation for API versioning?

: Yes. Vendor media types with version numbers are a common versioning strategy.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro