Ruby request headers but also a ?tag=tag - ruby

I am trying to send an API call to consul using a ruby script and I have a command that should be close to what I need but I can't get the rest to work.
RestClient::Request.execute(method: :get, url: path, timeout: 10, headers: {params: {"tag": tag, "X-Consul-Token" => encode_auth_token}})
Pretty much I need the call to be like if I did
curl --header "X-Consul-Token: <my token>" <my path>?tag=tag where the last tag in ?tag=tag is a variable and the token is a variable too.

You are extremely close, right now this does not work for you because the "X-Consul-Token" => 'AUTH_TOKEN' is being seen as a url parameter and not a header.
req.url
#=> "http://example.com?tag=tag&X-Consul-Token=AUTH_TOKEN"
req.headers
#=> {}
To fix this you just need to have params and the other header tags separated:
req= RestClient::Request.new(
method: :get,
url: 'http://example.com/',
timeout: 10,
headers: {params: {tag: 'tag'},
"X-Consul-Token" => 'AUTH_TOKEN'}) #notice outside of params
req.url
#=> "http://example.com?tag=tag"
req.headers
#=> {"X-Consul-Token"=>"AUTH_TOKEN"}

Related

Payload in Typhoeus Ruby Delete Request

I am trying to send request payload(like in a post call) with Typhoeus Delete call.
As far as I know, The latest update to the HTTP 1.1 specification (RFC 7231) explicitly permits an entity body in a DELETE request:
A payload within a DELETE request message has no defined semantics; sending a payload body on a DELETE request might cause some existing implementations to reject the request.
I tried this code, but body/payload is not retrievable
query_body = {:bodyHash => body}
request = Typhoeus::Request.new(
url,
body: JSON.dump(query_body),
method: :delete,
ssl_verifypeer: false,
ssl_verifyhost: 0,
verbose: true,
)
request.run
response = request.response
http_status = response.code
response.total_time
response.headers
result = JSON.parse(response.body)
At the other side, It comes in an encoded way, where I can not retrieve it
Other side code is like :
def destroy
respond_to do |format|
format.json do
body_hash = params[:bodyHash]
#do stuff
render json: {msg: 'User Successfully Logged out', status: 200}, status: :ok
end
format.all {render json: {msg: 'Only JSON types are supported', status: 406}.to_json, status: :ok}
end
end
Let me cite the specification:
A payload within a DELETE request message has no defined semantics;
sending a payload body on a DELETE request might cause some existing
implementations to reject the request.
I would NOT say it can be called as explicit permission to send payload with DELETE request. It tells you MAY send a payload, but the processing of such a request remains entirely at the discretion of the server.
And this is what happens:
At the other side, it comes in an encoded way, where I can not retrieve it
Why can't you send your payload as a part of POST request, which is guaranteed to be processed by the server normally?
I finally looked at all my requests in which I was payload (POST and PUT) and observed that I was not sending headers along with this DELETE request.
It looks something like this:
query_body = {:bodyHash => body}
request = Typhoeus::Request.new(
url,
body: JSON.dump(query_body),
method: :delete,
ssl_verifypeer: false,
ssl_verifyhost: 0,
verbose: true,
headers: {'X-Requested-With' => 'XMLHttpRequest', 'Content-Type' => 'application/json; charset=utf-8', 'Accept' => 'application/json, text/javascript, */*', 'enctype' => 'application/json'}
)
request.run
response = request.response
http_status = response.code
response.total_time
response.headers
result = JSON.parse(response.body)
Just adding headers to it, made it work

HTTPs Request in Ruby with parameters

I'm trying to pull data from a RESTful JSON web service which uses https. They provided a Curl example which works no problem; however, I'm trying to run the query in Ruby and I'm not a Ruby developer.
Any help much appreciated!
cURL example:
curl -G "https://api.example.com/v1/query/" \
-H "Accept: application/vnd.example.v1+hal+json" \
-u "$API_KEY:$API_SECRET" \
-d "app_id=$APP_ID" \
-d "days=3" \
-d "metrics=users" \
-d "dimensions=day"
My attempt in Ruby which is resulting in a HTTPUnauthorized 401:
require 'net/https'
require 'uri'
# prepare request
uri = URI.parse("https://api.example.com/v1/query/")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
request = Net::HTTP::Get.new(uri.request_uri, {
'Accept' => 'application/vnd.example.v1+hal+json',
'api_key' => 'api_secret',
'app_id' => 'app_id',
'days' => '3',
'metrics' => 'users',
'dimensions' => 'day'})
response = http.request(request)
response.body
response.status
response["header-here"] # All headers are lowercase
# Analyze the response
if response.code != "200"
puts "Error (status-code: #{response.code})\n#{response.body}"
print 0
else
print 1
end
** Update **
As per feedback below, I've installed Typhoeus and updated the request. Now I'm getting through. Thanks all!
request = Typhoeus::Request.new(
"https://api.example.com/v1/query/",
userpwd: "key:secret",
params: {
app_id: "appid",
days: "3",
metrics: "users",
dimensions: "day"
},
headers: {
Accept: "application/vnd.example.v1+hal+json"
}
)
First you need to realize that:
'Accept' => 'application/vnd.example.v1+hal+json'
is a header, not a parameter.
Also:
$API_KEY:$API_SECRET
is basic HTTP authentication, not a parameter.
Then, take my advice and go with a better Ruby HTTP client:
https://github.com/lostisland/faraday (preferred, a wrapper for the bellow)
https://github.com/typhoeus/typhoeus
https://github.com/geemus/excon
Update:
Try the following from IRB:
Typhoeus::Config.verbose = true # this is useful for debugging, remove it once everything is ok.
request = Typhoeus::Request.get(
"https://api.example.com/v1/query/",
userpwd: "key:secret",
params: {
app_id: "appid",
days: "3",
metrics: "users",
dimensions: "day"
},
headers: {
Accept: "application/vnd.example.v1+hal+json"
}
)
curl's -u sends the Authorization header. so your 'api_key' => 'api_secret', should be replaced with this one(once again, its http header, not parameter).
"Authorization" => "Basic ".Base64.encode64("api_key:api_secret")
## require "base64"

Rest-Client: how to post multipart/form-data?

I have to implement the curl POST request below listed, in Ruby, using Rest-Client.
I have to:
send params in header;
send params (that do not contain a file) as multipart/form-data:
$ curl -X POST -i -H "Authorization: Bearer 2687787877876666686b213e92aa3ec7e1afeeb560000000001" \
https://api.somewhere.com/endpoint -F sku_id=608399
How can I translate the curl request using the RestClient rubygem?
Reading documentation (multipart paragraph): https://github.com/rest-client/rest-client
I coded as:
#access_token = 2687787877876666686b213e92aa3ec7e1afeeb560000000001
url = 'https://api.somewhere.com/endpoint'
req = { authorization: "Bearer #{#access_token}"}
RestClient.post url, req, {:sku_id => 608399, :multipart => true}
But I get a server error; is the Ruby code above correct?
Thanks a lot,
Giorgio
Since I had trouble understanding the example Dmitry showed, here is an example for creating a Multipart request to upload an image:
response = RestClient.post 'https://yourhost.com/endpoint',
{:u_id => 123, :file => File.new('User/you/D/cat.png', 'rb'), :multipart => true},
{:auth_token => xyz5twblah, :cookies => {'_cookie_session_name' => cookie}}
It's code not valid for RestClient implementation.
headers should follow after payload.
module RestClient
def self.post(url, payload, headers={}, &block)
...
end
end
UPDATE
#access_token should be a string "2687787877876666686b213e92aa3ec7e1afeeb560000000001"
then
RestClient.log = 'stdout'
RestClient.post url, {:sku_id => 608399, :multipart => true}, req
and log
RestClient.post "https://api.somewhere.com/endpoint", "--330686\r\nContent-Disposition: form-data; name=\"sku_id\"\r\n\r\n608399\r\n--330686--\r\n", "Accept"=>"*/*; q=0.5, application/xml", "Accept-Encoding"=>"gzip, deflate", "Authorization"=>"Bearer 2687787877876666686b213e92aa3ec7e1afeeb560000000001", "Content-Length"=>"79", "Content-Type"=>"multipart/form-data; boundary=330686"

Using Bubblewrap: How to formulate get with custom headers?

I have the following Curl command that works:
curl -H "Authorization:GoogleLogin auth=xxx" http://www.google.com/reader/api/0/user-info
I'm trying to do this via a get in BubbleWrap HTTP:
HTTP.get("http://www.google.com/reader/api/0/user-info",
{
:headers => { "Authorization:GoogleLogin auth" => "xxx"}
}) do |response|
puts response
puts response.body.to_str
end
But I get a 401 back so maybe I didn't set the header correctly?
The header name is supposed to be Authorization with a value of GoogleLogin auth=xxx. The way you're doing it, it's a header name of Authorization:GoogleLogin auth with a value of xxx. Try this instead:
:headers => {"Authorization" => "GoogleLogin auth=xxx"}

Specifying Content Type in rspec

I'm trying to build an rspec test that sends JSON (or XML) via POST. However, I can't seem to actually get it working:
json = {.... data ....}.to_json
post '/model1.json',json,{'CONTENT_TYPE'=>'application/json'}
and this
json = {.... data ....}.to_json
post '/model1.json',json,{'Content-Type'=>'application/json'}
any ideas? THANKS!
In Rails 3, you can skip the header and #request.env stuff and just add a format parameter to your post call, e.g.:
post :create, format: :json, param: 'Value of Param'
There's a way to do this described in this thread -- it's a hack, but it seems to work:
#request.env["HTTP_ACCEPT"] = "application/json"
json = { ... data ... }.to_json
post :create, :some_param => json
A lot of frustration and variations and that's what worked for me.
Rails 3.2.12 Rspec 2.10
#request.env["HTTP_ACCEPT"] = "application/json"
#request.env["CONTENT_TYPE"] = "application/json"
put :update, :id => 1, "email" => "bing#test.com"
First of all, you don't want to test the built-in conversion of json to hash. Same applies to xml.
You test controller with data as hashes, not bothering wether it's json, xml or from a html form.
But if you would like to do that as an exercise, this is a standalone ruby script to do play with :)
require 'json'
url = URI.parse('http://localhost:3030/mymodels.json')
request = Net::HTTP::Post.new(url.path)
request.content_type="application/json"
request.basic_auth('username', 'password') #if used, else comment out
hash = {:mymodel => {:name => "Test Name 1", :description => "some data for testing description"}}
request.body = hash.to_json
response = Net::HTTP.start(url.host, url.port) {|http| http.request(request)}
puts response
to switch to xml, use content_type="text/xml" and
request.body = "<?xml version='1.0' encoding='UTF-8'?><somedata><name>Test Name 1</name><description>Some data for testing</description></somedata>"
A slightly more elegant test is to use the header helper:
header "HTTP_ACCEPT", "application/json"
json = {.... data ....}.to_json
post '/model1.json', json
Now this does exactly the same thing as setting #env; it's just a bit prettier.
The best way that I have found to test these things is with request tests. Request tests go through the full param parsing and routing stages of Rails. So I can write a test like this:
request_params = {:id => 1, :some_attribute => "some value"}
headers = {'Accept' => 'application/json', 'Content-Type' => 'application/json'}
put "/url/path", request_params.to_json, headers
expect(response).to be_success
I think that you can specify the headers with headers param:
post '/model1.json', headers: {'Content-type': 'application/json'}
Following the Rspec documentation of how provide JSON data.
#request.env["CONTENT_TYPE"] = "application/json"
OR pass in request
"CONTENT_TYPE" => "application/json"

Resources