How to view the X-Shopify-Shop-Api-Call-Limit - ruby

I want to view this specific header: X_SHOPIFY_SHOP_API_CALL_LIMIT
When I do this:
CreateShopifyClientService.call(shop)
begin
response = ShopifyAPI::InventoryLevel.find(:all, params: { inventory_item_ids: product.inventory_item_id})
byebug
rescue Exception => e
byebug
end
I've tried just about everything I can think of, including looking thru the tests on the gem and cannot find the mysterious header.
Here are some of my futile attempts:
(byebug) ap response.header
*** NoMethodError Exception: undefined method "header' for #<ShopifyAPI::PaginatedCollection:0x000055b39213c9c8>
(byebug) ap response.headers
*** NoMethodError Exception: undefined method "headers' for #<ShopifyAPI::PaginatedCollection:0x000055b39213c9c8>

I just did this in my terminal and it worked a peach...
shop = Shop.first
session = ShopifyAPI::Auth::Session.new(
shop: shop.shopify_domain,
access_token: shop.shopify_token
)
client = ShopifyAPI::Clients::Rest::Admin.new(
session: session
)
response = client.get(path: "products")
p response.headers["x-shopify-shop-api-call-limit"]
["1/40"]
=> ["1/40"]
So it is not too terribly hard to access the response headers. I see you're getting the response of the API call and not the HTTP response itself, so it seems you need to approach it differently for those old API calls. Maybe try updating to the more modern API and see if that helps you out.

Related

In Ruby/Sinatra, how to halt with an ERB template and error message

In my Sinatra project, I'd like to be able to halt with both an error code and an error message:
halt 403, "Message!"
I want this, in turn, to be rendered in an error page template (using ERB). For example:
error 403 do
erb :"errors/error", :locals => {:message => env['sinatra.error'].message}
end
However, apparently env['sinatra.error'].message (aka the readme and every single website says I should do it) does not expose the message I've provided. (This code, when run, returns the undefined method `message' for nil:NilClass error.)
I've searched for 4-5 hours and experimented with everything and I can't figure out where the message is exposed for me to render via ERB! Does anyone know where it is?
(It seems like the only alternative I can think of is writing this instead of the halt code above, every time I would like to halt:
halt 403, erb(:"errors/error", :locals => {m: "Message!"})
This code works. But this is a messy solution since it involves hardcoding the location of the error ERB file.)
(If you were wondering, this problem is not related to the show_exceptions configuration flag because both set :show_exceptions, false and set :show_exceptions, :after_handler make no difference.)
Why doesn't it work − use the source!
Lets look at the Sinatra source code to see why this problem doesn't work. The main Sinatra file (lib/sinatra/base.rb) is just 2043 lines long, and pretty readable code!
All halt does is:
def halt(*response)
response = response.first if response.length == 1
throw :halt, response
end
And exceptions are caught with:
# Dispatch a request with error handling.
def dispatch!
invoke do
static! if settings.static? && (request.get? || request.head?)
filter! :before
route!
end
rescue ::Exception => boom
invoke { handle_exception!(boom) }
[..]
end
def handle_exception!(boom)
#env['sinatra.error'] = boom
[..]
end
But for some reason this code is never run (as tested with basic "printf-debugging"). This is because in invoke the block is run like:
# Run the block with 'throw :halt' support and apply result to the response.
def invoke
res = catch(:halt) { yield }
res = [res] if Fixnum === res or String === res
if Array === res and Fixnum === res.first
res = res.dup
status(res.shift)
body(res.pop)
headers(*res)
elsif res.respond_to? :each
body res
end
nil # avoid double setting the same response tuple twice
end
Notice the catch(:halt) here. The if Array === res and Fixnum === res.first part is what halt sets and how the response body and status code are set.
The error 403 { .. } block is run in call!:
invoke { error_block!(response.status) } unless #env['sinatra.error']
So now we understand why this doesn't work, we can look for solutions ;-)
So can I use halt some way?
Not as far as I can see. If you look at the body of the invoke method, you'll see that the body is always set when using halt. You don't want this, since you want to override the response body.
Solution
Use a "real" exception and not the halt "pseudo-exception". Sinatra doesn't seem to come with pre-defined exceptions, but the handle_exception! does look at http_status to set the correct HTTP status:
if boom.respond_to? :http_status
status(boom.http_status)
elsif settings.use_code? and boom.respond_to? :code and boom.code.between? 400, 599
status(boom.code)
else
status(500)
end
So you could use something like this:
require 'sinatra'
class PermissionDenied < StandardError
def http_status; 403 end
end
get '/error' do
#halt 403, 'My special message to you!'
raise PermissionDenied, 'My special message to you!'
end
error 403 do
'Error message -> ' + #env['sinatra.error'].message
end
Which works as expected (the output is Error message -> My special message to you!). You can return an ERB template here.
In Sinatra v2.0.7+, messages passed to halt are stored in the body of the response. So a halt with an error code and an error message (eg: halt 403, "Message!") can be caught and rendered in an error page template with:
error 403 do
erb :"errors/error", locals: { message: body[0] }
end

How to handle exceptions with Ruby Rest-Client

I recently switched from Ruby's Net:HTTP class to rest-client 1.6.7.
I find it a lot easier to form requests, but unlike Net:HTTP request, when rest-client gets anything other than a 200, the request dies. I've tried putting a breakpoint directly after the RestClient.get, and it never gets hit - so I'm doing something wrong.
def get_member_using_card
resource = "#{#settings_app_uri}api/v1/card/#{self.member_card_num}?token=#{#settings.api_key}"
response = RestClient.get resource
if response.code == 200
card = JSON.parse(response.body)
self.customer_id = card['card']['customer_id']
else
return 0
end
end
Which results in this stacktrace:
RestClient::ResourceNotFound - 404 Resource Not Found:
/Users/tim/.rvm/gems/ruby-1.9.2-p290/gems/rest-client-1.6.7/lib/restclient/abstr
act_response.rb:48:in `return!'
/Users/tim/.rvm/gems/ruby-1.9.2-p290/gems/rest-client-1.6.7/lib/restclient/reque
st.rb:230:in `process_result'
/Users/tim/.rvm/gems/ruby-1.9.2-p290/gems/rest-client-1.6.7/lib/restclient/reque
st.rb:178:in `block in transmit'
/Users/tim/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/net/http.rb:627:in `start'
/Users/tim/.rvm/gems/ruby-1.9.2-p290/gems/rest-client-1.6.7/lib/restclient/reque
st.rb:172:in `transmit'
/Users/tim/.rvm/gems/ruby-1.9.2-p290/gems/rest-client-1.6.7/lib/restclient/reque
st.rb:64:in `execute'
/Users/tim/.rvm/gems/ruby-1.9.2-p290/gems/rest-client-1.6.7/lib/restclient/reque
st.rb:33:in `execute'
/Users/tim/.rvm/gems/ruby-1.9.2-p290/gems/rest-client-1.6.7/lib/restclient.rb:68
:in `get'
Can someone tell me how to properly evaluate the response code and keep this exception from happening...?
See heading Exceptions on http://rubydoc.info/gems/rest-client/
for results code between 200 and 207 a RestClient::Response will be returned
for results code 301, 302 or 307 the redirection will be followed if the request is a get or a head
for result code 303 the redirection will be followed and the request transformed into a get
for other cases a RestClient::Exception holding the Response will be raised, a specific exception class will be thrown for know error codes
RestClient.get 'http://example.com/resource'
➔ RestClient::ResourceNotFound: RestClient::ResourceNotFound`
begin
RestClient.get 'http://example.com/resource'
rescue => e
e.response
end
➔ 404 Resource Not Found | text/html 282 bytes
Also in the same documentation #wich pointed to, you can pass a block to RestClient.get such that it will not throw an exception on non-200 response codes:
# Don't raise exceptions but return the response
RestClient.get('http://example.com/resource'){|response, request, result| response }
See the "Result Handling" section from the documentation.
rescue RestClient::ExceptionWithResponse => err
There are several errors that could happen, specific exception types like Errno::EHOSTUNREACH or the more generic ExceptionWithResponse. Check the readme for more info.
I believe the best way to handle exceptions of an API client is to get the original error message thrown by the API endpoint. Here is an example code to handle that with RestClient
require 'json'
def get_call
begin
standard_response = {body: nil, success: false, message: ''}
response = RestClient.get('https://example.com/api/v1/xx', headers={'Authorization' => 'AbcDef xxx'})
standard_response[:success] = true
standard_response[:body] = JSON.parse(response.body)
rescue RestClient::ExceptionWithResponse => e
http_body = JSON.parse(e.http_body) # This is the original response from the API endpoint. e.g. {'message': 'Reason for the failure'}
meaningful_error_message = http_body['message'].nil? ? e.message : http_body['message'] # if {'message': 'error message'} is the format of your API
standard_response[:message] = meaningful_error_message
end
standard_response
end
Beautiful way to handle the exceptions in rest client.
For more info do check rest-client#response-callbacks-error-handling
RestClient.get('http://example.com/resource') { |response, request, result, &block|
case response.code
when 200
p "It worked !"
response
when 423
raise SomeCustomExceptionIfYouWant
else
response.return!(&block)
end
}

uncaught exception with net/http request wrapper in ruby

I have a script that calls the facebook test api to automate test account creation. At seemingly random interval, from either after 50 requests to 6000 requests, I get an exception that isn't caught. I'm at a loss for how to figure out what the error is, so I'll start with the relevant code here.
I'm not using the URI library because facebook keys have the pipe character that breaks URI.parse for ruby 1.8.7.
require 'rubygems'
require 'net/https'
require 'json'
http = Net::HTTP.new(domain, 443)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
def request_wrapper(http, request)
retry_count = 5
begin
return http.request(request)
rescue Exception => e
retry_count--
if retry_count < 0
raise e
end
retry
end
for i in 0..500 do
request = Net::HTTP::Get.new('https://' + domain + path)
response = request_wrapper(http, request)
end
The code will work for some time, but always inevitably reports the following:
in rescue in request_wrapper': undefined method-#' for nil:NilClass
(NoMethodError)
Anyone ever seen this undefined method '-#' before? Again, this happens very intermittently, but it's been a real thorn in my side. It always point to the line in the code where I am calling the request wrapper.
Thanks for taking a look.
The problem is with the line retry_count--. This line gets evaluated only when a failed HTTP request raises an Exception, which explains why it occurs intermittently.
Ruby does not have a unary decrement (--) or increment (++) operator. Matz has outlined the philosophical reasons behind this here. Also see this thread and this one for more information.
Instead, retry_count -= 1 should do the job.

Faraday (Ruby) Timeout Errors

I'm attempting to put a small payload generated in route A (Sinatra app) to Route B using Faraday. So the code basically looks like:
post "/routeA" do
foo.save
foo_id = foo.id
conn = Faraday.new(:url => "http://localhost:3001/routeB" ) do |builder|
builder.request :url_encoded
builder.response :logger
builder.adapter :net_http
end
resp = conn.put do |req|
req.url '/routeB'
req.headers['Content-Type'] = 'application/json'
req.body = {:id => foo_id }.to_json
req.options = {
#:timeout => 5, # see below, these aren't the problem
#:open_timeout => 2
}
end
# never gets here b/c Timeout error always thrown
STDERR.puts resp.body
end
put "/routeB" do
# for test purposes just log output
STDERR.puts request.body.read.to_s.inspect
status 202
body '{"Ok"}'
end
Problem is that it always throws a timeout error (I've run without the timeout options, and with the ones shown above -> same results). However, the logs show the request is going through:
I, [2012-03-24T16:56:13.241329 #17673] INFO -- : put http://localhost:3001/routeB
D, [2012-03-24T16:56:13.241427 #17673] DEBUG -- request: Content-Type: "application/json"
#<Faraday::Error::TimeoutError>
DEBUG - POST (60.7987ms) /routeA - 500 Internal Server Error
"{\"id\":7}"
DEBUG - PUT (0.0117ms) /routeB - 202 Accepted
Not sure how to get past the timeout error? Any insight would be appreciated. Thanks.
The problem is that the application cannot respond to another request until it's finished with the current one. That is, when you make a PUT request on the /routeB, the application got that, and it's waiting for the current request (/routeA) to finish. But the request won't finish because it's waiting to get the response from the /routeB. I think this is what causes the timeout error.

Ruby rest_client and windows LIVE connect OAUTH Wrap

Hi all I am trying to get my rails app to talk to Windows LIVE (through OAuth Wrap) so I can retrieve a list of contacts. I am using the rest_client gem to do this. Here is the action code for it:
def hotmail
app_id = 'some_id'
app_sec = 'some_secret'
app_callback = 'http://my.callback.com/same/as/getting/verification_code'
app_var = params[:wrap_verification_code]
encoded = "wrap_client_id=#{app_id}&wrap_client_secret=#{app_sec}&wrap_verification_code=#{app_var}&wrap_callback=#{app_callback}".encode!('UTF-8')
begin
r = RestClient.post("https://consent.live.com/AccessToken.aspx", encoded.bytes.to_a, {:content_type => 'application/x-www-form-urlencoded', :content_length => encoded.bytesize})
rescue => e
puts e.message
end
render :text => 'hello'
end
I base this on a c# example http://msdn.microsoft.com/en-us/library/ff750952.aspx (note: http://www.goatly.net/2010/12/23/401-unauthorized-when-acquiring-an-access-token-windows-live-sdk.aspx shows the correct payload)
However I keep getting 401 Unauthorized, so I am thinking is the way I am using rest_client incorrectly? During a form post is there somthing else I need to do?
ANy hints will be really helpful :) thanks in advance.
Found the problem. The C# code says it post the byte array but thats not true just post the encoded st direct is enough.

Resources