Add data fields to a rest-client request in Ruby - ruby

I am having trouble making a request to the uber api using the rest-client gem. I believe the issue is that I am trying to pass the required information as parameters in the url instead of data field. The example curl request has that parameters after -d, but I don't know how to implement that with rest-client. Thanks for the help.
This request works in the console:
curl -v -H "Authorization: Bearer " + session[:request_token] \
-H "Content-Type: application/json" -X POST -d \ '{"start_latitude":"37.334381","start_longitude":"-121.89432","end_latitude":"37.77703","end_longitude":"-122.419571","product_id":"a1111c8c-c720-46c3-8534-2fcdd730040d"}' \
https://sandbox-api.uber.com/v1/requests
Request from my controller that gets an error of 406, not acceptable response.
#uber_ride = JSON.load(RestClient::Request.execute(
:method => :post,
:url => "https://sandbox-api.uber.com/v1/sandbox/requests/product_id=#{#uberx_id}?start_latitude=#{lat_start}&start_longitude=#{lng_start}&end_latitude=#{lat_end}&end_longitude=#{lng_end}",
:headers => {'Authorization' => 'Bearer ' + session[:request_token], 'content_type' => 'application/json'}
))
I tried adding an additional field for data but that give a 404 Resource Not Found error.
#uber_ride = JSON.load(RestClient::Request.execute(
:method => :post,
:url => "https://sandbox-api.uber.com/v1/sandbox/requests/",
:data => {'start_latitude' => lat_start, 'start_longitude' => lng_start, 'end_latitude' => lat_end, 'end_longitude' => lng_end, 'product_id' => #uberx_id},
:headers => {'Authorization' => 'Bearer ' + session[:request_token]},
:content_type => :json
))

I finally got it working. Thanks #mudasobwa for the recommendation of changing data => to payload =>. I also had to add single quotes around the payload object so the rest-client gem wouldn't convert it out of json. ex: '{}'. Lastly, I had to change how I specified the content-type and specify it in :headers, as :content_type, NOT 'Content-Type'. See below for the final request that is now working. It's a bit messy with the variables being .to_s, but after 5 hours this is the only call I could get working.
#uber_ride = (RestClient::Request.execute(
:method => :post,
:url => "https://sandbox-api.uber.com/v1/requests",
:payload => '{"start_latitude":' + lat_start.to_s + ',"start_longitude":' + lng_start.to_s + ',"end_latitude":' + lat_end.to_s + ',"end_longitude":' + lng_end.to_s + ',"product_id":"' + #uberx_id.to_s + '"}',
:headers => {'Authorization' => 'Bearer ' + session[:request_token], :content_type => 'application/json'}
))
Happy to hear any feedback on how I could clean this up.

Related

POST JSON data with Curl Multi from ruby

I am using the curb gem to do a Curl Multi post using JSON data. However I am unable to actually get the parameters to get posted and have been unable to figure out how to properly configure the parameters.
urls = [
{
:url => "http://localhost:5000/",
:method => :post,
:headers => {'Accept' => 'application/json', 'Content-Type' => 'application/json'},
:post_fields => {'field1' => 'value1', 'k' => 'j'}
}
]
Curl::Multi.http(urls) do |easy, code, method|
puts "#{easy.body_str.inspect}, #{method.inspect}, #{code.inspect}"
end
=>
"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n<title>400 Bad Request</title>\n<h1>Bad Request</h1>\n<p>The browser (or proxy) sent a request that this server could not understand.</p>\n", :post, nil
Do that:
urls = [
{
:url => "http://localhost:5000/",
:method => :post,
:headers => {'Accept' => 'application/json', 'Content-Type' => 'application/json'},
:post_fields => {},
:post_body => {'field1' => 'value1', 'k' => 'j'}.to_json,
}
]
The problem: curb doesn't know that you are sending a JSON data. Curb don't read and interprets the contents of :headers. As you can see here, curb transforms your hash into a string separated by "&", which is the default for a normal (non-json) http data sending (eg.: "field1=value1&k=j"). When the server (Rails) read and interprets the header explicity saying that the data is in JSON format, it tries to decode and the result is the same exception that you get when you do that: JSON.parse("field1=value1&k=j").
To solve this, you need to send "post_fields" as an empty hash, and send your actual data by using "post_body". Also, you need to convert your hash to json manually with to_json.
I don't know if they (the curb project owners) know this problem, but I suggest you to warning them about it.

How do I use RestClient to post as URL params?

I am posting to an API which accepts CURL as follows:
curl -v -X POST "https://url.com" -d 'input=frustrated&user_key=3b9ccb48e734fce6b982a9c1c2cef301'
I have tried the following with an error:
data = {'user_key' => "#{ENV['USER_KEY']}", 'input' => "#{text}", 'client_name'=>> "#{client_name}"}
talkresponse = JSON.parse(RestClient.post url_talk_bot, {:params => data})
for some reason, the data is fine for all except for 'input' which always gets an error as an array which triggers an error since a string is expected. Note below how the input params is an array.
{"user_key"=>"3b9ccb48e734fce6b982a9c1c2cef301", "input"=>"[\"frustrated how do I post to params, worked fine before\"]", "client_name"=>"14155086888"}
/mnt/task/__gems__/gems/rest_client-1.7.3/lib/restclient/abstract_response.rb:48:in `return!': 401 Unauthorized (RestClient::Unauthorized)
I have run into similar issues when using RestClient.post.
So much so, that I stopped using .post and started using .execute
RestClient.post uri, {:params => data}
becomes
RestClient.execute({ :method => :post, :url => uri, :headers => {api_key: '123', authorization: Base64::encode("#{user}:#{password}"}, :payload: body})

How can I get HTTParty to recognize ":footer" and ":collector" parameters?

I received the following code from a development team:
curl -u EMAILADDRESS:PASSWORD -d "sender=NAME <EMAILADDRESS>&message=[Invite Link]&collector=COLLECTOR&subject=Test Invite&footer=My Custom Text [Unsubscription Link]"
I have been told that the above works fine. This is what I translated it to in Ruby 1.9.3, using the httparty gem:
call= "/api/v2/emails/?survey=#{i}"
puts collector_final_id
url= HTTParty.post("https://www.fluidsurveys.com#{call}",
:basic_auth => auth,
:headers => { 'Content-Type' => 'application/x-www-form-urlencoded','Accept' => 'application/x-www-form-urlencoded' },
:collector => collector,
:body => {
"subject" => "Test Invite",
"sender" => "NAME <EMAILADDRESS>",
"message" => "[Invite Link]"
},
:footer => "My Custom Text [Unsubscription Link]"
)
Everything within this works fine except for the :footer and :collector parameters. It doesn't seem to recognize them at all.
There are no errors thrown, they just aren't included in the actual email I am sending. What am I doing wrong when passing in those two parameters?
Your :collector and :footer are not correct.
I wrote a little Sinatra service to receive a POST request with any parameters:
require 'pp'
require 'sinatra'
post "/*" do
pp params
end
And ran it, launching the web-server on my Mac OS laptop. As Sinatra apps do, it resides at 0.0.0.0:4567.
Running this code:
require 'httparty'
url = HTTParty.post(
"http://localhost:4567/api/v2/emails?survey=1",
:headers => {
'Content-Type' => 'application/x-www-form-urlencoded',
'Accept' => 'application/x-www-form-urlencoded'
},
:body => {
"subject" => 'subject',
"sender" => 'sender',
"message" => 'message',
},
:collector => 'collector',
:footer => 'footer'
)
puts url
Outputs:
["survey", "1"]["subject", "subject"]["sender", "sender"]["message", "message"]["splat", ["api/v2/emails"]]["captures", ["api/v2/emails"]]
Sinatra said:
127.0.0.1 - - [11/Sep/2013 17:58:47] "POST /api/v2/emails?survey=1 HTTP/1.1" 200 - 0.0163
{"survey"=>"1",
"subject"=>"subject",
"sender"=>"sender",
"message"=>"message",
"splat"=>["api/v2/emails"],
"captures"=>["api/v2/emails"]}
Changing :collector and :footer to strings and moving them inside the body, where they should be:
require 'httparty'
url = HTTParty.post(
"http://localhost:4567/api/v2/emails?survey=1",
:headers => {
'Content-Type' => 'application/x-www-form-urlencoded',
'Accept' => 'application/x-www-form-urlencoded'
},
:body => {
"subject" => 'subject',
"sender" => 'sender',
"message" => 'message',
'collector' => 'collector',
'footer' => 'footer'
},
)
puts url
Outputs:
["survey", "1"]["subject", "subject"]["sender", "sender"]["message", "message"]["collector", "collector"]["footer", "footer"]["splat", ["api/v2/emails"]]["captures", ["api/v2/emails"]]
And Sinatra said:
127.0.0.1 - - [11/Sep/2013 18:04:13] "POST /api/v2/emails?survey=1 HTTP/1.1" 200 - 0.0010
{"survey"=>"1",
"subject"=>"subject",
"sender"=>"sender",
"message"=>"message",
"collector"=>"collector",
"footer"=>"footer",
"splat"=>["api/v2/emails"],
"captures"=>["api/v2/emails"]}
The problem is, the POST request ONLY uses a URL and a :body hash. Inside the :body hash go all the variables you're sending to the server. That's why the second version of the code, with 'collector' and 'footer' works.
There is no comma after your :body parameter

Setting Request Headers in Ruby

I have the rest client gem and I am defining a request like this:
url = 'http://someurl'
request = {"data" => data}.to_json
response = RestClient.post(url,request,:content_type => :json, :accept => :json)
However I need to set the HTTP header to something. For example an API key. Which could be done in curl as:
curl -XHEAD -H x-auth-user: myusername -H x-auth-key: mykey "url"
Whats the best way to do this in ruby? Using this gem? Or can I do it manually to have more control.
The third parameter is the headers hash.
You can do what you want by:
response = RestClient.post(
url,
request,
:content_type => :json, :accept => :json, :'x-auth-key' => "mykey")
You can also do this
RestClient::Request.execute(
:method => :get or :post,
:url => your_url,
:headers => {key => value}
)
I had the same problem with Rest-Client (1.7.2) I need to put both params and HTTP headers.
I solved with this syntax:
params = {id: id, device: device, status: status}
headers = {myheader: "giorgio"}
RestClient.put url, params, headers
I hate RestClient :-)
If PUT isn't allowed we can pass it in the header of POST. Headers in bold. This worked for me:
act_resp = RestClient.post url, req_param, **:content_type => :json, :method => :put**

Ruby Multi-part Form Upload with RestClient

I'm working on a ruby application, and am trying to upload a file to box.net. I have it working with the curl call
curl https://www.box.com/api/2.0/files/data -H "Authorization: BoxAuth api_key=<API_KEY>&auth_token=<AUTH_TOKEN>" -F folder_id=0 -F filename=#test.txt --trace ~/Desktop/log.txt
I've tried to translate this into ruby, and have tried the following
request = RestClient::Request.new(:method => :post,:url => "https://www.box.com/api/2.0/files/data",:authorization => "BoxAuth api_key=<API_KEY>&auth_token=<AUTH_TOKEN>",:filename => "test.txt", :payload => { :multipart => true, :file => File.new("test.txt"))
request.execute
but I keep getting back a "401: Unauthorized" response. I've also tried using the box-api gem, but that seems to only work with version 1.0 of the API, and I'm trying to interface with 2.0.
Try to use :headers => {:authorization => "BoxAuth api_key=<API_KEY>&auth_token=<AUTH_TOKEN>"} in the call. That should fix the missing authorization header.
Complete request would then be:
request = RestClient::Request.new(:method => :post,:url => "https://www.box.com/api/2.0/files/data",:headers => {:authorization => "BoxAuth api_key=<API_KEY>&auth_token=<AUTH_TOKEN>"},:filename => "test.txt", :payload => { :multipart => true, :file => File.new("test.txt")})

Resources