Always set content type

This is part of the Semicolon&Sons Code Diary - consisting of lessons learned on the job. You're in the web-development category.

Last Updated: 2024-04-24

Why Content-Type headers are needed for HTML docs

I uploaded a static website to s3 but it had a problem. When I visited the index.html file in Chrome, the file was downloaded instead of rendered. Inspecting the HTML headers, its Content-Type was wrong: Instead of 'text/html' it was "Content-Type: binary/octet-stream". Thus the downloading. The fix was to set the content-type when uploading the object to s3.

Why Content-Type headers are needed for JavaScript AJAX calls

I installed DebugBar into some PHP code. To my surprise, this broke various client-side JavaScript endpoints in development. This is because these endpoints expected data in JSON or XML formats and then parsed them client-side. However, DebugBar appends itself to the output from the server. This sorta makes sense, since where else could it possibly appear, it being an exclusively backend-installed tool?

I looked into the DebugBar features, and it knows to hide itself when it's a JSON or XML content-type. My current JavaScript code specified nothing about Content-Type (I was trying to be economical) so therefore the hiding was not triggered during my XML/JSON requests.

After specifying the Content-Type headers for these requests, everything worked.

Incident 3

JSON post APIs often require two application/json entries: Content-Type and Accept

I had the following code:

def get(url)
  ...
  request = Net::HTTP::Get.new(url)
  # Important bit:
  request['accept'] = 'application/json'
  request['api-key'] = api_key

  response = http.request(request)
  parse_response_as_json(response)
end

def post(url, data = {})
  ...
  request = Net::HTTP::Post.new(url)
  # Important bit:
  request['accept'] = 'application/json'
  request['api-key'] = api_key
  request.body = data.to_json

  response = http.request(request)
  parse_response_as_json(response)
end

The get method worked but the post returned error 406 - "not acceptable"

This was confusing because the methods seemed symmetrical. In reality, what was missing was the "content-type" header for the POST method. Here's the fix

...
request['accept'] = 'application/json'
request['content-type'] = 'application/json'

The reason this is needed is in order for the server to know how to deal with the payload.

Note a potential confusion here: both GET and POST responses from the server will have a content type. However POST requests also have one, since the payload may be significant in size.

Lesson

Always set content-type headers for requests