HTTP Headers and Content Negotiation

beginner
11 min

HTTP Headers and Content Negotiation

Headers are the metadata layer of HTTP: key-value pairs that travel with every request and response, describing the payload, the caller, caching rules, and more. Mastering a dozen headers will cover 95 percent of your REST API work. In this lesson we tour the essential headers and then dig into content negotiation, the mechanism that lets one endpoint serve many formats.

Request Headers You Will Use Constantly

  • Host: the domain being addressed; mandatory in HTTP/1.1.
  • Authorization: credentials, most often Bearer <token> for APIs.
  • Content-Type: the format of the body you are sending, such as application/json.
  • Accept: the formats you are willing to receive.
  • User-Agent: identifies the client software; useful for analytics and debugging.
  • If-None-Match: enables conditional requests for caching (paired with ETag).
http
GET /api/reports/2026-q2 HTTP/1.1 Host: api.finlytics.io Authorization: Bearer eyJhbGciOi... Accept: application/json If-None-Match: "v3-8c1d"

Response Headers That Matter

  • Content-Type: what the body actually is. Clients trust this, so get it right.
  • Cache-Control: how long clients and proxies may cache the response, like max-age=300.
  • ETag: a version fingerprint of the resource. When the client sends it back via If-None-Match and nothing changed, the server answers 304 Not Modified with an empty body, saving bandwidth.
  • Location: where a newly created resource lives (with 201) or where to redirect.
  • Retry-After: how long to wait after a 429 or 503.
  • Access-Control-Allow-Origin: the CORS header that decides which browser origins may read your API's responses. Without it, browser-based clients on other domains are blocked.

Content Negotiation: One URL, Many Formats

Content negotiation lets the same resource URL serve different representations depending on what the client asks for. The client states preferences with Accept; the server picks the best match and confirms its choice with Content-Type.

http
GET /api/invoices/881 HTTP/1.1 Accept: application/pdf HTTP/1.1 200 OK Content-Type: application/pdf

The same endpoint could return JSON to a web app (Accept: application/json) and a PDF to a billing tool, without inventing separate URLs like /invoices/881.pdf. Accept values can carry quality weights, such as Accept: application/json;q=1.0, application/xml;q=0.5, meaning JSON is preferred but XML is acceptable. If the server supports none of the requested formats, the correct response is 406 Not Acceptable.

Negotiation also covers language (Accept-Language: hi-IN, en) and compression (Accept-Encoding: gzip, br). Compression negotiation happens almost invisibly: the server compresses the body, sets Content-Encoding: gzip, and clients decompress automatically. For JSON APIs this routinely cuts payload sizes by 70 to 90 percent.

Custom Headers

APIs often add their own headers, conventionally prefixed by the product name: X-RateLimit-Remaining tells callers how many requests they have left, and X-Request-Id carries a correlation ID that lets you trace one request across microservices and log files. Keep custom headers few and documented; anything essential to the business data belongs in the body instead.

Key Takeaways

  • Content-Type describes the body being sent; Accept describes what the caller wants back.
  • ETag with If-None-Match enables 304 responses that skip re-sending unchanged data.
  • CORS headers control which browser origins can consume your API.
  • Content negotiation serves multiple formats, languages, and encodings from a single URL.

Next up: Designing Resource URLs, where we learn to name endpoints like a professional.

HTTP Headers and Content Negotiation - REST APIs | CodeYourCraft | CodeYourCraft