How to check header of request inside a method using Rspec? - ruby-on-rails

I have a method that will hit other API. And I made a condition to decide which auth token that will be used while posting to that API. Example:
class OrderFee
def perform
get_pricing
end
private
def get_pricing
payload = {
from: "a",
to: "b"
}
authorization = ''
if Config.UsingFirstToken?
authorization = "first_token"
else
authorization = "second_token"
end
response = Connection.MyCourier.post(url, payload) do |req|
req.headers['Authorization'] = authorization
end
response.body
end
end
I want to make 2 test case using Rspec to make sure if Config.UsingFirstToken true, it will hit the API using first_token, and otherwise. I can check the return value of this method, but I can't find a way to expect header from that POST action

You have access to the request object in your spec.
Expect what the header equals like this:
expect(request.headers['Authorization']).to eq("first_token")
Or whatever you expect the token to be.

Related

RSpec tests for RestClient::Request.execute: Any way to see the request?

I am using RestClient gem to build an API client and the calls to the API are processed by this method here
def call(api_name,api_endpoint,token = nil,*extra_params)
endpoint = fetch_endpoint(api_name,api_endpoint)
params = {}
endpoint['params'].each_with_index { |p,i| params[p] = endpoint['values'][i] }
puts params
if token.nil? then
response = RestClient::Request.execute(method: endpoint['method'], url: endpoint['url'], params: params.to_json)
else
response = RestClient::Request.execute(method: endpoint['method'], url: endpoint['url'], headers: {"Authorization" => "Bearer #{token}"}, params: params.to_json)
end
response
end
As you may see, all I do is mounting a hash with parameters/values for the call and invoking RestClient::Request#execute to get a response.
It happens that some of my tests, like this one
it 'request_autorization' do
obj = SpotifyIntegration.new
response = obj.call('spotify','request_authorization',nil,state: obj.random_state_string)
myjson = JSON.parse(response.body)
expect(myjson).to eq({})
end
are returning a 400 Bad request error, and I really don't know why. Other tests, like this one
it 'my_playlists (with no authorization token)' do
obj = SpotifyIntegration.new
expect {
response = obj.call('spotify','my_playlists')
}.to raise_error(RestClient::Unauthorized,'401 Unauthorized')
end
processed by the same method, run perfectly fine.
Is there any way to see the request sent? I mean, see how RestClient is mount/sending my request to the corresponding API? May be this way I could understand what is happening.
By "see the request" I mean something like
puts RestClient::Request.prepared_request
or
puts RestClient::Request.prepared_url
I've searched the RestClient documentation and found nothing similar, but maybe some of you know how to do this.
You might try using RestClient.log to get more information. Something like:
RestClient.log = STDOUT
WebMock is also a great test framework for HTTP requests. The tests for rest-client itself make a lot of use of WebMock.

Is there any way to move Devise's headers response to body?

In my Rails-api app I'am using Devise gem which when authenticating returns all crucial info (Access-Token, UID, Client etc) in Headers, like this:
Access-Token →DIbgreortZbCYKqzC8HdNg
Client →Y6J5oTIqS7Gc_-h9xynBQ
Uid →email2#example.com
I want those to be in the response Body. Is there any way to achieve this?
Rails provides you with a request object so you can grab whatever you need out of the headers in your controller.
def some_action
#mime_type = request.headers["Content-Type"] # => "text/plain"
#token = request.headers["key-for-your-token-here"]
end
You can then either pass it to your view or you can insert it into the response body via request.bodyas you would insert any key/value pair into a hash.
Documentation for ActionDispatch::Request found here:
http://api.rubyonrails.org/classes/ActionDispatch/Request.html#method-i-headers
UPDATE:
Make a custom method and see how long it has to run to navigate the header hash. If long you can use it to find the exact nesting of what you're looking for and change it.
def find_token(parent, request.headers)
request.headers.each {|key, value|
if value.is_a?(Hash)
find_token(key, value)
elsif key == 'THE TOKEN KEY HERE'
return value
else
next
end
}
end

what is Instagram API basic access in sandbox?

I try to use instagram API in sandbox.
I use Ruby with gem 'instagram'
But I can only call method
Instagram.user_recent_media( {:count => 5})
def user_recent_media(*args)
options = args.last.is_a?(Hash) ? args.pop : {}
id = args.first || "self"
response = get("users/#{id}/media/recent", options)
response
end
like #instagram = Instagram.user_recent_media( {:count => 5})
I try to call other method like
def follow_user(id, options={})
options["action"] = "follow"
response = post("users/#{id}/relationship", options, signature=true)
response
end
get
Instagram::BadRequest in HomeController#index
GET
https://api.instagram.com/v1/users/[user_ID]/follows.json?access_token=[Access_token]&max_id=10:
400: This request requires scope=follower_list, but this access token
is not authorized with this scope. The user must re-authorize your
application with scope=follower_list to be granted this permissions.
Is there any method I can use ??
instagram-ruby-gem API
Basically, you have to register your application with Instagram here and hope they accept it. There isn't a way around this.
Here's a little reading on how they basically said "buzz off" to third party app developers http://www.businessinsider.com/instagram-made-a-change-that-stopped-lots-of-third-party-apps-from-working-2016-6

Is there a way to set the default namespace with Savon::Model?

Savon is stubborn in generating SOAP envelopes from WSDL's. It does it improperly and I see no way to fix it. It also takes the liberty of inserting the wsdl: namespace on everything for whatever reason.
The request I am building uses the tns: namespace. I'd love to be able to use Savon::Model, but right now I have to do:
client.request :tns, :function_name do
soap.body = { params }
end
Instead of something like:
super(params)
Making the request block in every function is tedious, and I have to define the function name every time instead of Savon automatically calling the correct function like what would happen in the ideal case. Right now my functions are looking like
def foo
client.request :tns, :foo do
...
end
Having to say "foo" twice seems ridiculous. Is there a way to set the default namespace for every request in a class that extends Savon::Model?
client = Savon.client do
wsdl "blah blah"
element_form_default :qualified
namespace_identifier :tem
env_namespace :soapenv
end
I am not sure if I understand your questions. I assume you are asking how to set the default namespace and wrap the request body in a function, so you don't need to write the request body every time. This code works for me, but I removed some irrelevant parts
class ExampleWS
EXAMPLE_WS_DEFAULT_NAMESPACE = "urn:example:request:1.0.0"
......
def getStockPrice( locale, stockId )
response = $client.request :get_stock_price do
soap.input = [
"ns1:getStockPrice",
{
"xmlns:ns1" => EXAMPLE_WS_DEFAULT_NAMESPACE #set default namespace here
}
]
soap.body = {
"locale" => locale,
"stockId" => stockId
}
end
end
......
end
......
# call the function
getStockPrice("en_US", 123 )
This works for me. It uses Savon 2, though:
class Soapservice
extend Savon::Model
client wsdl: "http://example.com?wsdl", env_namespace: :tns,
operations :get_resource, :put_resource
def :get_resource(id)
super(message: { id: id })
end
end
service = Soapservice.new
response = service.get_resource(1) #overwriting get_resource
# or
response = service.put_resource(message: { username: "luke", secret: "secret" })
(My example builds on the one from the official savon homepage)

Problems with MailChimp API in Ruby Error Code: -90

I am using the following code in my MailChimp Controller to submit simple newsletter data. When It is sent I receive the following error as a "Method is not exported by this server -90" I have attached my controller code below. I am using this controller for a simple newsletter signup form. (Name, Email)
class MailchimpController < ApplicationController
require "net/http"
require "uri"
def subscribe
if request.post?
mailchimp = {}
mailchimp['apikey'] = 'f72328d1de9cc76092casdfsd425e467b6641-us2'
mailchimp['id'] = '8037342dd1874'
mailchimp['email_address'] = "email#gmail.com"
mailchimp['merge_vars[FNAME]'] = "FirstName"
mailchimp['output'] = 'json'
uri = URI.parse("http://us2.api.mailchimp.com/1.3/?method=listSubscribe")
response = Net::HTTP.post_form(uri, mailchimp)
mailchimp = ActiveSupport::JSON.decode(response.body)
if mailchimp['error']
render :text => mailchimp['error'] + "code:" + mailchimp['code'].to_s
elsif mailchimp == 'true'
render :text => 'ok'
else
render :text => 'error'
end
end
end
end
I highly recommend the Hominid gem: https://github.com/tatemae-consultancy/hominid
The problem is that Net::HTTP.post_form is not passing the "method" GET parameter. Not being a big ruby user, I'm not certain what the actual proper way to do that with Net::HTTP is, but this works:
require "net/http"
data="apikey=blahblahblah"
response = nil
Net::HTTP.start('us2.api.mailchimp.com', 80) {|http|
response = http.post('/1.3/?method=lists', data)
}
p response.body
That's the lists() method (for simplicity) and you'd have to build up (and urlencode your values!) your the full POST params rather than simply providing the hash.
Did you take a look at the many gems already available for ruby?
http://apidocs.mailchimp.com/downloads/#ruby
The bigger problem, and main reason I'm replying to this, is that your API Key is not obfuscated nearly well enough. Granted I'm used to working with them, but I was able to guess it very quickly. I would suggest immediately going and disabling that key in your account and then editing the post to actually have completely bogus data rather than anything close to the correct key. The list id on the other hand, doesn't matter at all.
You'll be able to use your hash if you convert it to json before passing it to Net::HTTP. The combined code would look something like:
mailchimp = {}
mailchimp['apikey'] = 'APIKEYAPIKEYAPIKEYAPIKEY'
mailchimp['id'] = '8037342dd1874'
mailchimp['email_address'] = "email#gmail.com"
mailchimp['merge_vars[FNAME]'] = "FirstName"
mailchimp['output'] = 'json'
response = nil
Net::HTTP.start('us2.api.mailchimp.com', 80) {|http|
response = http.post('/1.3/?method=listSubscribe', mailchimp.to_json)
}

Resources