16

I am having difficulty making a POST request to an API endpoint using Ruby's HTTParty library. The API I'm interacting with is the Gittip API and their endpoint requires authentication. I have been able to successfully make an authenticated GET request using HTTParty.

You can see in the example code:

user = "gratitude_test"
api_key = "5962b93a-5bf7-4cb6-ae6f-aa4114c5e4f2"
# I have included real credentials since the above is merely a test account.

HTTParty.get("https://www.gittip.com/#{user}/tips.json", 
             { :basic_auth => { :username => api_key } })

That request works and returns the following as expected:

[
  {
    "amount" => "1.00",
    "platform" => "gittip",
    "username" => "whit537"
  },
  {
    "amount" => "0.25",
    "platform" => "gittip",
    "username" => "JohnKellyFerguson"
  }
]

However, I have been unable to make a successful POST request using HTTParty. The Gittip API describes making a POST request using curl as follows:

curl https://www.gittip.com/foobar/tips.json \
  -u API_KEY: \
  -X POST \
  -d'[{"username":"bazbuz", "platform":"gittip", "amount": "1.00"}]' \
  -H"Content-Type: application/json"

I have tried (unsuccessfully) structuring my code using HTTParty as follows:

user = "gratitude_test"
api_key = "5962b93a-5bf7-4cb6-ae6f-aa4114c5e4f2"

HTTParty.post("https://www.gittip.com/#{user}/tips.json",
              { 
                :body => [ { "amount" => "0.25", "platform" => "gittip", "username" => "whit537" } ],
                :basic_auth => { :username => api_key },
                :headers => { 'Content-Type' => 'application/json' }
               })

The first argument is the url and the second argument is an options hash. When I run the code above, I get the following error:

NoMethodError: undefined method `bytesize' for [{"amount"=>"0.25", "platform"=>"gittip", "username"=>"whit537"}]:Array
  from /Users/John/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/2.0.0/net/http/generic_request.rb:179:in `send_request_with_body'

I have tried various other combinations of structuring the API call, but can't figure out how to get it to work. Here's another such example, where I do not user an array as part of the body and convert the contents to_json.

user = "gratitude_test"
api_key = "5962b93a-5bf7-4cb6-ae6f-aa4114c5e4f2"

HTTParty.post("https://www.gittip.com/#{user}/tips.json",
          {
            :body => { "amount" => "0.25", "platform" => "gittip", "username" => "whit537" }.to_json,
            :basic_auth => { :username => api_key },
            :headers => { 'Content-Type' => 'application/json' }
           })

Which returns the following (a 500 error):

<html>
  <head>
    <title>500 Internal Server Error</title>
  </head>
  <body>\n        Internal server error, program!\n        <pre></pre>  
  </body>
</html>

I'm not really familiar with curl, so I'm not sure if I am incorrectly translating things to HTTParty.

Any help would be appreciated. Thanks.

John K. Ferguson
  • 641
  • 2
  • 8
  • 15

1 Answers1

37

Just a guess, but it looks like you're passing a hash in the body when JSON is expected.

Try replacing the :body declaration with:

:body => [{ "amount" => "0.25", 
             "platform" => "gittip", 
             "username" => "whit537" }].to_json

Edit: I suggested the to_json serializer, but misplaced it by putting it after the hash instead of the array and removing the array altogether. The example uses multiple records, so the array is necessary.

After looking at this thread, it looks like Gittip is picky about the accept header.

:headers => { 'Content-Type' => 'application/json', 'Accept' => 'application/json'}

So, the full suggestion is:

HTTParty.post("https://www.gittip.com/#{user}/tips.json",
  { 
    :body => [ { "amount" => "0.25", "platform" => "gittip", "username" => "whit537" } ].to_json,
    :basic_auth => { :username => api_key },
    :headers => { 'Content-Type' => 'application/json', 'Accept' => 'application/json'}
  })
Community
  • 1
  • 1
d_ethier
  • 3,873
  • 24
  • 31
  • Hey, thanks, I just tried your suggestion but still got the same error as before. – John K. Ferguson Oct 19 '13 at 02:47
  • Updated answer, you might want to remove the array declaration too. `bytesize` is a string method so executing it on a hash or array will not work. You can see the ruby source [here](https://github.com/ruby/ruby/blob/trunk/lib/net/http/generic_request.rb). – d_ethier Oct 19 '13 at 03:02
  • I tried your suggestion without the array and got a 500 error. I edited my post to describe what happened in detail. – John K. Ferguson Oct 19 '13 at 03:11
  • Wow, that worked!!! Thank you so much!!! I had been struggling with this for a while so I really appreciate your help. – John K. Ferguson Oct 19 '13 at 08:02
  • @d_ethier, thanks for this. Curious, you are sending both a body and a header - is the header required? – cheshireoctopus Mar 25 '14 at 19:46
  • 1
    @cheshireoctopus, I'm not 100% sure. I based this example on the answers in [this question](http://stackoverflow.com/questions/7455744/post-json-to-api-using-rails-and-httparty) which seems to indicate that the headers were necessary. – d_ethier Mar 26 '14 at 14:01
  • "you're" - no I am not trolling – defbyte Sep 26 '15 at 04:37