skip to content

questions

4

In HTTP, what is the Accept request header for, and what is a server expected to do with it?

level: juniorimportance: must knowfreq 62%

answer

  1. Accept = what I can read back
  2. Content-Type = what these bytes are
  3. media range: type/subtype, type/*, */*
  4. no Accept ≈ */*
  5. negotiated ⇒ Vary: Accept

basics

~20 s

Accept is a request header listing the media types a client can handle, such as application/json or text/html. The server picks one representation of the resource from that list and names its choice in the response Content-Type header.

solid answer

~50 s

`Accept` is how a client tells the server **which media types it can understand in the response body**. It is a comma-separated list of media ranges, e.g. `Accept: application/json, text/html`. This is *proactive (server-driven) content negotiation*: one URL may have several representations and the server chooses one. The server intersects what the client accepts with what it can produce, picks the best match, and answers with `Content-Type` naming the chosen type. `Content-Type` on the response is the answer to `Accept` on the request. Two things trip people up. First, `Accept` describes the **response**; the `Content-Type` a client sends describes its own **request body** — opposite directions. Second, `Accept` is advisory: a server may ignore it and serve a default. If the response really was negotiated, the server should send `Vary: Accept` so a shared cache doesn't hand a JSON body to an HTML-only client.

code

http · 10 lines
http
GET /users/42 HTTP/1.1
Host: api.example.com
Accept: application/json, text/html

HTTP/1.1 200 OK
Content-Type: application/json
Vary: Accept
Content-Length: 41

{"id":42,"name":"Ada","role":"engineer"}

go deeper

for a junior

Know the one-liner: Accept says what I can receive, response Content-Type says what I got. Give a JSON/HTML example.

for a middle

Add the mechanics: media ranges and wildcards, absent Accept means /, and Vary: Accept for caches.

for a senior

Frame it as proactive negotiation with an advisory contract, discuss client robustness (always read Content-Type) and the CDN cache-poisoning failure mode when Vary is missing.

for a principal

Discuss whether to negotiate at all — many teams pin one representation per URL for cacheability and debuggability, and reserve Accept negotiation for image formats or API versioning where the payoff is concrete.

## The problem it solves One URL can stand for a resource with several *representations*: `/users/42` might be renderable as JSON, as XML, or as an HTML page. Choosing among them is **content negotiation**. In the *proactive* (server-driven) form defined by RFC 9110, the client states its capabilities up front in `Accept`-family request headers and the server decides. ## Syntax `Accept` carries a comma-separated list of **media ranges**. Each range is `type/subtype` optionally followed by parameters after semicolons: ``` Accept: application/json, text/html, image/*, */* ``` `type/subtype` is an exact media type. `type/*` matches any subtype of that type. `*/*` matches anything. Ranges may also carry weights (`;q=…`) which express relative preference; weights are a topic of their own, and everything below holds when no weights are present. An absent `Accept` header means the client accepts anything — it is equivalent to `Accept: */*`, not an error. ## What the server does with it 1. Determine the set of representations it can produce for that resource (JSON only, or JSON + XML + HTML…). 2. Discard those the client did not accept. 3. Among the survivors, choose one — using the client's stated preference first, then its own preference as a tiebreaker. 4. Send the chosen representation with a `Content-Type` header that names exactly what was sent. Step 4 is the part candidates forget. The response is not self-describing without `Content-Type`; the client should read the actual `Content-Type`, not assume the server honoured its first choice. If nothing survives step 2, the server has two legitimate options — refuse with `406 Not Acceptable`, or ignore `Accept` and send its default. Which one real servers pick is a separate discussion. ## Direction matters: Accept vs Content-Type - Request `Accept: application/json` → "send me JSON back." - Request `Content-Type: application/json` → "the bytes I am sending you *are* JSON." - Response `Content-Type: application/json` → "the bytes I am sending you are JSON." There is no `Accept` header on a response. A POST commonly carries both: `Content-Type` for the body it sends, `Accept` for the body it wants back, and they need not be the same (`Content-Type: application/x-www-form-urlencoded` with `Accept: application/json` is ordinary). ## The Accept family The same request-side pattern repeats for other axes of negotiation: `Accept-Language` for natural language, `Accept-Encoding` for compression, and the obsolete `Accept-Charset`. Each has a matching response header that reports what was actually chosen — `Content-Language`, `Content-Encoding`. ## Caching A negotiated response is only valid for clients that sent a compatible `Accept`. The server signals that with: ``` Vary: Accept ``` This tells shared caches to key the stored entry on the request's `Accept` value. Omitting it is a classic production bug: the first request warms the cache with JSON and an HTML-only browser is later served that JSON from the CDN. ## What Accept is really used for in practice - **APIs** that emit JSON by default but can emit XML, CSV, or a problem document. - **Browsers**, which send a long list like `text/html,application/xhtml+xml,image/avif,image/webp,*/*` so a server can return AVIF to a modern browser and JPEG to an old one from the same URL. - **Versioned APIs** using vendor media types such as `application/vnd.example.v2+json`. ## What it is not It is not a field filter (that is a query parameter concern), not a compression control (`Accept-Encoding` does that), and not binding on the server. A server that only ever produces JSON is entitled to produce JSON regardless of what `Accept` says — many do exactly that, and clients must tolerate it.

  • What does a server do if the request has no Accept header at all?
    An absent Accept means the client has no stated preference and will take anything — it is treated as `*/*`. The server should serve its default representation, not an error. Returning 406 because the header is missing is a bug.
  • Why should a negotiated response carry Vary: Accept?
    Because the response body depends on a request header, a shared cache must not reuse it for a request whose Accept differs. `Vary: Accept` makes Accept part of the cache key. Without it a CDN can serve the JSON representation to a client that asked only for HTML.
  • If a client sends Accept: application/json and the server sends back text/html, what should the client do?
    Read the response Content-Type and handle it — Accept is a preference, not a contract. A robust client checks the actual Content-Type before parsing, and treats an unexpected type as an error case rather than blindly feeding an HTML error page to a JSON parser.

Accept is the diner saying "I can eat anything vegetarian or fish"; Content-Type is the waiter putting down the plate and saying "this is the sea bass". The kitchen may still bring something off-list.

saying these in an interview costs you the question

  • Saying Accept and Content-Type are the same header or interchangeable.
  • Claiming Accept describes the request body being sent.
  • Insisting the server MUST return one of the listed types or fail.
  • Thinking a missing Accept header is an error worth rejecting.
  • Never mentioning that the response's own Content-Type reports the actual choice.

context

open as a page

How does the HTTP Accept-Language header work, and why is the Accept-Charset header effectively obsolete?

level: middleimportance: should knowfreq 36%

basics

~20 s

Accept-Language lists language tags such as en-GB or fr that a client prefers for the response; the server picks a translation and reports it in Content-Language. Accept-Charset is obsolete because everything is UTF-8 now, so browsers stopped sending it.

open as a page

A client sends `Accept: text/html, text/*, */*` in an HTTP request. Explain what the wildcards `text/*` and `*/*` mean and how a server decides which media type to serve.

level: middleimportance: should knowfreq 45%

basics

~20 s

They are media ranges of decreasing specificity: an exact type, any subtype of text, then anything. A server matches its available representations against them and the most specific matching range wins, so an HTML representation is preferred here.

open as a page

What are vendor media types such as `application/vnd.github+json` in an HTTP Accept header, and how are they used to select an API version?

level: seniorimportance: should knowfreq 34%

basics

~20 s

They are media types in the vendor registration tree (vnd.) naming an organisation's own format, usually with a structured suffix like +json. A client asks for one in Accept, e.g. application/vnd.example.v2+json, and the server returns that variant and echoes it in Content-Type.

open as a page