Ruby putting token key in requests - ruby

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

Related

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...

opt_fields not working with Asana API but url works in the Asana explorer

I'm using Ruby starting from the "hello world" example. Hello world works find. I'm trying to get this GET to work:
GET /projects/192372431230306/tasks?opt_fields=id,assignee,due_on,name,notes&limit=10&completed_since=now
It works exactly as expected in the Asana API explorer.
I'm using the same URI in my code:
uri = URI.parse("https://app.asana.com/api/1.0/projects/192372431230306/tasks?opt_fields=id,assignee,due_on,name,notes&limit=10&completed_since=now")
It still returns ID and Name correctly, but it's not what I want.
I can't see why it works in the explorer but not in the GET request. I am using the personal token and the explorer uses OAuth.
My personal token is set correctly before this code. I can create tasks, get projects, get tasks. I just can't more fields in this query like the API explorer.
Added Code:
uri = URI.parse("https://app.asana.com/api/1.0/projects/192372431230306/tasks?opt_fields=id,assignee,due_on,name,notes&limit=10&completed_since=now")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
# set up the request
header = {
"Content-Type" => "application/json"
}
req = Net::HTTP::Get.new(uri.path, header)
req.basic_auth(personal_access_token, '')
res = http.start { |http| http.request(req) }
body = JSON.parse(res.body)
puts "projects: #{body['data']}"
There isn't quite enough code here to know what's wrong. It sounds like your code is working to some degree, but maybe there's something different between using a personal token as opposed to OAuth. According to the Asana API documentation:
Personal Access Tokens should be used similarly to OAuth access tokens when accessing the API, passing them in the Authorization header:
curl -H "Authorization: Bearer ACCESS_TOKEN" https://app.asana.com/api/1.0/users/me
So in addition to the URL, you need to use the correct headers. I'm not sure what HTTP library you use, but here's how I would do it with HTTParty:
require 'uri'
require 'httparty'
uri = URI.parse("https://app.asana.com/api/1.0/projects/192372431230306/tasks?opt_fields=id,assignee,due_on,name,notes&limit=10&completed_since=now")
task = HTTParty.get(uri,
:headers =>
{'Authorization' => "Bearer ${ENV[ACCESS_TOKEN]}"}
).parsed_response
If you put your personal access token in the ACCESS_TOKEN environment variable, that should correctly authenticate you for the request.
Still, it seems like there's something else missing if you can get all the fields. Maybe your personal access token is associated with a different account than your OAuth access token? It might help to check the results of /users/me/ route?

URI.parse doesn't want to parse uri with | (pipe) char

I'm trying to send get request with:
require "net/https"
require "uri"
...
uri = "https://graph.facebook.com/v2.2/#{event_id}?access_token=#{access_token}"
uri = URI.parse(uri)
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)
response = http.request(request)
response.body
Facebook sent me an acces_token with | char, and because of it uri = URI.parse(uri) throws an error: URI::InvalidURIError: bad URI(is not URI?) https:/ ....
Is there any other parser, or should I manually extract these host, port, request_uri values? What's the best way of fixing it?
access_token looks like 141112112181111|9Alz3xW7P0CQ_DRomJN2oMeiwXs
event_id is for example 385101904985590
edit: just realized that it's structure is APP_ID|some_token
Have you tried encoding the URI with URI#encode?
uri = 'http://foobar.com?foo=something|weird'
uri = URI.encode(uri)
uri = URI.parse(uri) => #<URI::HTTP:0x007fe2f48775b0 URL:http://foobar.com?foo=something%7Cweird>
Don't try to inject variables into URI query parameters, especially tokens and keys and such as that's a good route to creating an invalid one. Instead, rely on the URI class and let it handle as much as possible.
require 'uri'
event_id = 1
access_token = 'foo|bar'
uri = URI.parse("https://graph.facebook.com/v2.2/#{event_id}")
uri.query = URI.encode_www_form(['access_token', access_token])
uri.to_s # => "https://graph.facebook.com/v2.2/1?access_token&foo%7Cbar"
If you want something more full-featured, Addressable::URI is very nice.
See "Parsing string to add to URL-encoded URL" for more information.

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"}

POST request with Ruby and Calabash

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

Resources