Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I make Ruby's RestClient gem respect content_type on post?

For instance, in the RestClient console:

RestClient.post 'http://localhost:5001', {:a => 'b'}, :content_type => 'application/json'

This does not send application/json as the content type. Instead I see:

Content-Type: application/x-www-form-urlencoded

I was able to trace the change to restclient/payload.rb:

  class UrlEncoded < Base
  ...

  def headers
    super.merge({'Content-Type' => 'application/x-www-form-urlencoded'})
  end
end

Replacing super.merge with super causes the content type to be respected, but obviously that's not a real solution. Does anyone know the proper way to fix this? Thanks.

like image 499
Nick Urban Avatar asked Nov 18 '11 22:11

Nick Urban


3 Answers

You might want to put json as string as your payload instead of hash. For example, do:

RestClient.post 'http://localhost:5001','{"a":"b"}',:content_type => 'application/json'

If you look at the payload.rb, it shows that it will use the Base clase instead of UrlEncoded class if the payload is string. Try that and see if that work for you.

like image 85
DrChanimal Avatar answered Nov 06 '22 22:11

DrChanimal


Fact:

For :post request, when payload is a Hash, the Content-Type header will be always overridden to application/x-www-form-urlencoded.

Reproduciable with rest-client (2.0.0).

Solution:

Convert the hash payload to json string.

require 'json'

payload.to_json

There is a ticket in rest-client's repo:

like image 45
Jing Li Avatar answered Nov 07 '22 00:11

Jing Li


I'd like to add that my issue was when using RestClient::Request.execute (as opposed to RestClient.post or RestClient.get).

The problem was with how I was setting :content_type and :accept. From the examples I saw it felt like they should be top level options like this:

res = RestClient::Request.execute(
  :method => :get,
  :url => url,
  :verify_ssl =>  false,
  :content_type => :json,
  :accept => :json,
  :headers => { 
    :Authorization => "Bearer #{token}", 
  },
  :payload => '{"a":"b"}'
)

But you actually have to put them within :headers like this:

res = RestClient::Request.execute(
  :method => :get,
  :url => url,
  :verify_ssl =>  false,
  :headers => { 
    :Authorization => "Bearer #{token}", 
    :content_type => :json,
    :accept => :json
  },
  :payload => '{"a":"b"}'
)
like image 10
Ryan Bosinger Avatar answered Nov 06 '22 23:11

Ryan Bosinger