How to check content-type of API response

Print the media type on its own with curl -s -o /dev/null -w '%{content_type}\n' https://httpbin.org/json, which returns application/json. To see the charset parameter and the exact spelling, read the raw header from a GET with -D -. Check the error path as well as the 200.

Why check this

The content type decides whether a client parses the body, renders it, or downloads it. A JSON route that answers text/html on its 404 makes every error handler fail, and a JSON route that answers text/plain stops a browser client that filters on media type. Run this on staging sign-off and after any change to a proxy, a CDN or a framework error page.

Prerequisites

Steps

  1. Step 1.

    Print the media type of a GET, with no other header noise.

    curl -s -o /dev/null -w '%{content_type}\n' https://httpbin.org/json
    
    application/json

    %{content_type} prints the header value in full, parameters included, so an empty line here means the server sent no content type at all.

  2. Step 2.

    Read the raw header line from a different API to see a charset parameter in place.

    curl -s -D - -o /dev/null https://api.github.com/repos/curl/curl | grep -i '^content-type'
    
    content-type: application/json; charset=utf-8
  3. Step 3.

    Ask the same service for a route that fails, and read what the error path sends.

    curl -s -o /dev/null -w '%{http_code} %{content_type}\n' https://httpbin.org/status/404
    
    404 text/html; charset=utf-8

    The success path of this host is JSON and its 404 is HTML. A client that parses every body without reading the header breaks on this route.

  4. Step 4.

    Confirm that the type is fixed and not negotiated, by asking for something else.

    curl -s -H 'Accept: application/xml' -o /dev/null -w '%{http_code} %{content_type}\n' https://httpbin.org/json
    
    200 application/json

    A service that honours Accept answers with a different type here, or with 406. This one ignores the header, which is worth writing down before a client team assumes otherwise.

  5. Step 5.

    Compare what a HEAD request reports with the GET from step 1.

    curl -sI https://httpbin.org/json | grep -i '^content-type'
    
    content-type: application/json

    The two agree here. A HEAD and a GET that disagree mean two code paths answer the route, and the one your client uses is the GET.

How to read the result

| What you see | What it means | What to do | | --- | --- | --- | | application/json | The type a JSON client expects | Nothing. Confirm the error routes send the same. | | application/json; charset=utf-8 | Correct type, redundant parameter | Harmless. RFC 8259 defines no charset for this media type. | | text/html; charset=utf-8 on an API route | HTML came back, most likely an error page | Read the status code, then parse the body to see who wrote it. | | text/plain on a JSON route | The type was never set, so a default applied | Set it in the handler. Browser clients that filter on type drop this response. | | An empty value | No content-type header at all | Browsers sniff the body, and X-Content-Type-Options: nosniff then blocks it. |

Thresholds

application/json takes no charset parameter. JSON text is always UTF-8 when exchanged between systems. Source: RFC 8259 section 8.1 and section 11, https://www.rfc-editor.org/rfc/rfc8259#section-11

Common mistakes

Sign: curl -I reports one type, the browser receives another.Cause: -I sends HEAD. Frameworks and CDNs often route HEAD through a shorter path that never reaches the handler setting the type. Read the header from a GET with -D - and -o /dev/null.
Sign: Only the 200 route was checked, and error handling breaks in production.Cause: Error bodies are written by the framework, the reverse proxy or the WAF, each with its own default type. Step 3 shows a host whose success is JSON and whose 404 is HTML.
Sign: The header looks right, so the media type is assumed correct.Cause: A header states intent, not content. A 502 page can carry application/json. Pair this check with a parse of the body before signing the route off.
Sign: An upload or download route sends application/json for a file.Cause: A generic middleware set the type for every response. The browser then renders bytes instead of saving them, and the filename in content-disposition is ignored.

What to check next

FAQ

How to check the content type of a response in the browser?

Open DevTools, Network tab, click the request, then the Headers panel and read Response Headers. The Type column in the request list shows a normalised label, not the header, so it hides text/plain served for JSON.

Should application/json carry charset=utf-8?

It is not required. RFC 8259 registers no charset parameter for the media type and mandates UTF-8 for interchange. Sending it is harmless, and removing it from an existing API is not worth a release on its own.

Why does my API return text/html only sometimes?

Because a different layer answered. Reverse proxies, WAFs and framework error pages write their own bodies with their own defaults. Compare the status code from step 3 with the one your handler intends to send.

Does content-type change what the server parses on a request?

It changes what the server parses on the way in, which is the request content type, a separate header of the same name. This procedure reads the response side only. Send Content-Type: application/json on POST bodies and check that route separately.

Verified

Verified by Maks Vernycurl 8.21.0

Each output block is what the command above it printed on that date, on the host named in the step. Figures read from a live site move between runs. Compare the shape of the answer rather than the digits, and see the methodology for how a page is re-verified.

basic3 minpublished updated Maks Verny