Josh Thompson     about     blog     ☕️ with josh

HTTParty and to_json

Article Table of Contents

I was having some trouble debugging an HTTParty POST request.

A few tools that were useful to me:

  1. post DEBUG info to STDOUT
  2. netcat to listen to HTTP requests locally

I had this code:

options = {
  headers: {
    "Content-Type": "application/json",
    authorization: "Bearer #{our_token}",
  query: { data: true },
  body: { token: their_token },
  debug_output: STDOUT

And when I posted it:"#{BASE_URL}/endpoint", options)

I kept getting something like this:

opening connection to
starting SSL for
SSL established
<- "POST /endpoint?data=true HTTP/1.1\r\nContent-Type: application/json\r\nAuthorization: Bearer alksdjflkajsdf\r\nHost:\r\nContent-Length: 1234\r\n\r\n"
<- "token=aslsdjfhasiudyfkajn"
-> "HTTP/1.1 400 Bad Request\r\n"
-> "Date: Mon, 11 Mar 2019 16:58:13 GMT\r\n"
-> "Content-Type: text/plain\r\n"
-> "Content-Length: 28\r\n"
-> "\r\n"
reading 28 bytes...
-> "Invalid json line 1 column 7"
read 28 bytes
Conn keep-alive
=> "Invalid json line 1 column 7"

Invalid json? The body was being passed into HTTParty as a hash, I had been assuming this would convert it to JSON.

body: { token: their_token },

So, I fired up netcat on localhost, to try making different POST requests and watch the formatting a little closer:

nc -l -k localhost 4000

I was seeing requests like so:

looks OK, right?

what was the solution?

My coworker John Livingston was chatting with me about a PR he had open, and asked for a review on an update to a Slack notification bot. I saw him use a suspicious method inside of his HTTParty request.

response =, {
        body: payload.to_json,
        headers: {'Content-Type' => 'application/json'}



Because I’d also been working on a different post request, where the Content-Type was application/x-www-form-urlencoded, I wasn’t actually looking to make sure the body was putting out JSON. Of course this isn’t JSON.

Not json: #


json: #


The fix? add .to_json on the request body:

options = {
  headers: {
    "Content-Type": "application/json",
    authorization: "Bearer #{our_token}",
  query: { data: true },
  body: { token: their_token }.to_json
  # I just added .to_json      ^^^^^^^

I’m writing this whole thing out because in hindsight it’s blindingly obvious what the problem was, but at the time I was really stuck on why the endpoint couldn’t parse the body as json.

Now we all know.