reference

content negotiation

format detection, terminal vs hal+json, and overrides

content negotiation

the api adapts response format based on who's asking.

detection

the User-Agent header determines format. case-insensitive substring match:

user-agent contains format
curl terminal
wget terminal
httpie terminal
fetch terminal
anything else json

no user-agent at all → json.

terminal format

plain text with auto-generated output from hal resources. collections render as tables, detail views as key-value pairs, tool results as formatted output.

every terminal response appends an available actions section — a plain-text version of the hal _links:

available actions:
  GET    /tools              browse developer tools
  GET    /apis               browse api catalog
  GET    /docs               browse documentation

content-type: text/plain; charset=utf-8.

json format

hal+json with full hypermedia links. some routes include curies for namespaced link relations:

{
  "_links": {
    "curies": [{
      "name": "gnu",
      "href": "https://api.gnu.foo/rels/{rel}",
      "templated": true
    }],
    "self": { "href": "/" },
    "gnu:tools": { "href": "/tools" }
  }
}

curies are compact uri templates — gnu:tools expands to https://api.gnu.foo/rels/tools, so custom link relations are resolvable urls, not opaque strings.

content-type: application/hal+json.

overrides

force json from a cli client:

curl -H "Accept: application/json" gnu.foo/tools
curl gnu.foo/tools?json

the ?json param takes priority over everything — user-agent and accept header are both ignored.

supported accept values: application/json, application/hal+json, application/vnd.hal+json, */*, application/*.

non-cli clients requesting an unsupported media type get 406:

{
  "type": "https://api.gnu.foo/errors/not-acceptable",
  "title": "not acceptable",
  "status": 406,
  "detail": "the requested media type is not supported. this API supports application/json and application/hal+json."
}

cli clients never get 406 — they always fall through to terminal format.

caching

all responses include Vary: Accept, User-Agent to ensure proper cache behavior across formats.