POST request with Ruby and Calabash - ruby

I use Calabsh to test iOS app. Duringtest I need to create POST request to change some values and then verify that changes are reflected in UI.
Request looks like:
wwww.testserver.com/userAddMoney?user_id=1&amount=999
To authorize on server I need to pass special parameters to Header of request:
Headers: X-Testing-Auth-Secret: kI7wGju76kjhJHGklk76

require 'net/http'
uri = URI.parse('http://www.testserver.com/userAddMoney?user_id=1&amount=999')
http = Net::HTTP.new(uri.host,uri.port)
## https.use_ssl = true # use https, need require net/https
req = Net::HTTP::Post.new(uri.path)
req['X-Testing-Auth-Secret'] = 'kI7wGju76kjhJHGklk76'
res = http.request(req)
Docs here: Net::HTTP::Post Net::HTTPSession

Related

Ruby putting token key in requests

I dont know how to put my key into my requests so they are sent back as
{"status"=>"400", "message"=>"Token parameter is required."}
This is the code I have been using
require 'net/http'
require 'json'
token = 'YiwwVvywLngtPT***************'
url = 'https://www.ncdc.noaa.gov/cdo-web/api/v2/stations?locationid=FIPS:23&limit=5&sortfield=mindate'
uri = URI(url)
response = Net::HTTP.get(uri)
response.authorization = token
puts JSON.parse(response)
I have tried a couple different things I've found on the internet but all of them just give errors for
undefined method `methodname' for #<String:0x00007fd97519abd0>
According to the API documentation (based on the URL you referenced), you need to provide the token in a header named token.
So, you should probably try some variation of the below (code untested):
token = 'YiwwVvywLngtPT***************'
url = 'https://www.ncdc.noaa.gov/cdo-web/api/v2/stations?locationid=FIPS:23&limit=5&sortfield=mindate'
uri = URI(url)
request = Net::HTTP::Get.new(uri)
request['token'] = token
response = Net::HTTP.start(uri.hostname, uri.port) do |http|
http.request(request)
end
More information about Net:HTTP headers can be found in this StackOverflow answer.
As a side note, if you are not locked on using Net::HTTP, consider switching to a friendlier HTTP client, perhaps HTTParty. Then, the complete code looks like this:
require 'httparty'
token = 'YiwwVvywLngtPT***************'
url = 'https://www.ncdc.noaa.gov/cdo-web/api/v2/stations?locationid=FIPS:23&limit=5&sortfield=mindate'
response = HTTParty.get url, headers: { token: token }
puts response.body

Ruby GET NET HTTP request does not work with AUTHORIZATION and ACCEPT when passed in a header

I've been using the code below to call a third party API . This code works fine (i've changed the url and the credentials but the structure of the code is the same) :
require 'base64'
require 'httparty'
require 'json'
######################################################################
# Get the token first
######################################################################
consumer_key = "my_key"
consumer_secret = "my_secret"
credentials = Base64.encode64("#{consumer_key}:#{consumer_secret}").gsub("\n", '')
url = "https://mysite/token"
body = "grant_type=client_credentials"
headers = {
"Authorization" => "Basic #{credentials}",
"Content-Type" => "application/x-www-form-urlencoded;charset=UTF-8"
}
r = HTTParty.post(url, body: body, headers: headers)
bearer_token = JSON.parse(r.body)['access_token']
######################################################################
# Use the token in a call as authorisation header
######################################################################
api_url = "https://apisite/the_value_i_am_looking_for_in_the_api"
url = URI.parse(api_url)
req = Net::HTTP.new(url.host, url.port)
req.use_ssl = true
# If we are just passing a key that doesn't need to be in the token format
headers = {
'Authorization' => "Bearer #{bearer_token}"
}
# Get the response back (he data is in the response body: resp.body )
resp = req.get(url, headers)
My issue is that the API providers have changed their API so you now need to pass an "accept" into the call via the header. I used POSTMAN to make the call, added the accept to the header and was able to get it working without issue. So far so good.
I then changed my ruby code to extend the headers section to include the accept, using the code below:
headers = {
'Authorization' => "Bearer #{bearer_token}",
'Accept' => 'application/vnd.bluebadge-api.v1+json'
}
I've not added an accept to a header before so I may have gotten the syntax wrong.
However, this returns an unauthorised 401 response code:
#<Net::HTTPUnauthorized 401 Unauthorized readbody=true>
I thought I might have the credentials wrong so remove the accept, try again and this changes to a 406 response code:
#<Net::HTTPNotAcceptable 406 Not Acceptable readbody=true>
If I examine the response I get the message I would expect that the accept header is not the supported version. So I know the credentials are correct (and the fact they match the postman credentials which works):
"{\"apiVersion\": \"1\",\"context\": null,\"id\": null,\"method\": null,\"error\": {\"code\": null,\"message\": null,\"reason\": \"Accept header version is not a currently supported version.\",\"errors\": null}}\n"
So I know all my credentials are correct because I've copied them into the postman request which works with no errors. The value for the accept header is correct because I copied that from a working postman request too.
I am at a loss for why this wouldn't work.
I've looked through the NET HTTP library and cant find anything to help me there. I've seen a couple of posts elsewhere which I've tried and they haven't worked either.
I appreciate any help in trying to solve this.
Found the problem. I was using the credentials from the production environment to get the token then trying to query the test environment API. In my defence they look very similar (only 3 characters different). I think I had a case of the code blindness.
The code I posted does work when I put the correct URL for the environments.
I also found that I could use this:
uri = URI.parse("https://myapi/some_text")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Get.new(uri.request_uri)
request["Authorization"] = "Bearer #{bearer_token}"
request["Accept"] = "application/vnd.bluebadge-api.v1+json"
response = http.request(request)
Or using HTTParty like this:
response = HTTParty.get('https://myapi/some_text', {
headers: {"Authorization" => "Bearer #{bearer_token}", "Accept" => "application/vnd.bluebadge-api.v1+json" }
})
I would prefer the format of my orginal code or the HTTparty code because it is easy to see from the code that you're passing headers. Hopefully this will help others to double check their authorization credentials...

How to add "Content-type" header in HTTP POST

I keep getting a
400 "Bad Request" (Net::HTTPServerException)
error whenever I try to add a content-type header from various methods.
I've seen several different examples and I can't get any to work. My goal is to add a content type of JSON to my request. Without the header, my request doesn't error:
def post_data(notice)
uri = URI('my uri is here')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
req = Net::HTTP::Post.new("#{uri.path}?#{uri.query}")
text = notice
req.add_field('Content-Type', 'application/json')
req.body = "{\"sensu_payload\" = #{payload(text).to_json}}"
response = http.request(req)
verify_response(response)
end
I've also tried this method of adding a header:
request = Net::HTTP::Post.new(#path, initheader = {'Content-Type' =>'application/json'})
Use uri.path instead of #path:
request = Net::HTTP::Post.new(uri.path, initheader = {'Content-Type' =>'application/json'})
Instead of add_field, I think you should use the hash [] form:
req['Content-Type'] = 'application/json'
See the "Setting Headers" example in the documentation and []=.
Also, using:
"#{uri.path}?#{uri.query}"
is never a good idea. String concatenation can't manage the complexities of correctly encoding illegal values in a query, which can break a request. Consider doing something like this instead:
require 'uri'
require 'uri'
foo = URI('http://www.example.com') # => #<URI::HTTP http://www.example.com>
foo.query = URI::encode_www_form({'bar' => 'path/to/file', 'baz' => 'this & that'})
foo.to_s # => "http://www.example.com?bar=path%2Fto%2Ffile&baz=this+%26+that"
Beyond that, I'd recommend using any of the other HTTP-client gems available. They make it much easier to deal with unexpected situations, like redirects and retries than Net::HTTP. It's more like the building block for features that aren't available other ways.

HTTP Basic Authentication as default in Ruby HTTP

Using Ruby 2.2.3 I'm looking for a way to use HTTP Basic Authentication for every request. I know it is possible to define basic_auth per request:
http = Net::HTTP.new(uri.host, uri.port)
request = Net::HTTP::Get.new(uri.request_uri)
request.basic_auth("username", "password")
response = http.request(request)
How can I "globally" use basic_auth?
basic_auth is an instance method of an Net::HTTP object. For convenience you could define a class with the desired basic_auth settings baked-in or given as arguments.
Simple example:
require 'uri'
require 'net/http'
class SimpleHTTP
def initialize uri, user = "default_user", pass = "default_pass"
#uri = URI.parse(uri)
#username = user
#password = pass
end
def request path=nil
#uri.path = path if path # use path if provided
http = Net::HTTP.new(#uri.host, #uri.port)
req = Net::HTTP::Get.new(#uri.request_uri)
req.basic_auth(#username, #password)
http.request(req)
end
end
# Simple Example
http = SimpleHTTP.new('http://www.yoursite.com/defaultpath')
http.request
# Override default user/pass
http2 = SimpleHTTP.new('http://www.yoursite.com/defaultpath', "myusername", "mypass")
http2.request
# Provide path in request method
http = SimpleHTTP.new('http://www.yoursite.com/')
http.request('/some_path')

Ruby httpclient url

I am making a call to a webservice via HTTPClient ruby gem. The location doesn't matter, but let's say it is at: https://mywebservice.com/api/v1/accounts/login/
When I send a post request:
url = "https://mywebservice.com/api/v1/accounts/login/"
client = HTTPClient.new
client.post url
I get a 404 response, that the page was not found. I setup a proxy and checked out exactly what was being sent it seems like the gem is messing up the url, it actually sends the request to:
https://mywebservice.comhttps://mywebservice.com:443/api/v1/accounts/login/
I am completely lost, I have no why it is doing that. Does it have anything to do with the fact that it's https and I should handle https differently?
Thanks
Yes, if you are requesting a https url do this:
require 'net/http'
require 'net/https'
require 'uri'
uri = URI.parse(url)
http = Net::HTTP.new(uri.host, uri.port)
request = Net::HTTP::Post.new(uri.request_uri)
#you need to set this field to true
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
response = http.request(request)
Here is a link that should help:
http://bibwild.wordpress.com/2012/04/30/httpclient-is-a-nice-http-client-forin-ruby/
You should post to an uri with a body of params. Something like
client.post "http://mysite.com:8080", data
where data is a hash with the required parameters for the page.
For instance:
data = {"var" => "var"}

Resources