How to rescue RestClient API calls in development mode when no Internet available? - ruby

In my Rails app I am making various API calls like this one:
class SearchFacebook
FALLBACK_STARS = 5.0
def self.call
begin
url = "https://graph.facebook.com/v2.12/#{FACEBOOK_PAGE_ID}"
response = RestClient.get(url, :params => {:access_token => FACEBOOK_ACCESS_TOKEN, :fields => "overall_star_rating"})
json = JSON.parse(response)
stars = json["overall_star_rating"]
rescue RestClient::ExceptionWithResponse => error
stars = FALLBACK_STARS
end
{:stars => stars}
end
end
The problem is that I am running my app in my local environment a lot of the time. When there's no Internet connection available (which happens a lot to me, don't ask why), I get the following error:
SocketError.
Failed to open TCP connection to api.facebook.com:443 (getaddrinfo:
nodename nor servname provided, or not known)
How can I rescue from being offline?
I checked RestClient documentation already but to no avail. Thanks for any help.

Can you use a blanket rescue => e and use byebug to inspect the exception being raised. You could then rescue that error if in a development environment.
There are some other options mentioned here Check if Internet Connection Exists with Ruby?

OK, I solved this by simply rescuing from a SocketError:
rescue SocketError, RestClient::ExceptionWithResponse => error
I found this answer quite helpful.

Related

404 not found, but can access normally from web browser

I tried many URLs on this and they seem to be fine until I came across this particular one:
require 'rubygems'
require 'nokogiri'
require 'open-uri'
doc = Nokogiri::HTML(open("http://www.moxyst.com/fashion/men-clothing/underwear.html"))
puts doc
This is the result:
/Users/macbookair/.rvm/rubies/ruby-2.0.0-p481/lib/ruby/2.0.0/open-uri.rb:353:in `open_http': 404 Not Found (OpenURI::HTTPError)
from /Users/macbookair/.rvm/rubies/ruby-2.0.0-p481/lib/ruby/2.0.0/open-uri.rb:709:in `buffer_open'
from /Users/macbookair/.rvm/rubies/ruby-2.0.0-p481/lib/ruby/2.0.0/open-uri.rb:210:in `block in open_loop'
from /Users/macbookair/.rvm/rubies/ruby-2.0.0-p481/lib/ruby/2.0.0/open-uri.rb:208:in `catch'
from /Users/macbookair/.rvm/rubies/ruby-2.0.0-p481/lib/ruby/2.0.0/open-uri.rb:208:in `open_loop'
from /Users/macbookair/.rvm/rubies/ruby-2.0.0-p481/lib/ruby/2.0.0/open-uri.rb:149:in `open_uri'
from /Users/macbookair/.rvm/rubies/ruby-2.0.0-p481/lib/ruby/2.0.0/open-uri.rb:689:in `open'
from /Users/macbookair/.rvm/rubies/ruby-2.0.0-p481/lib/ruby/2.0.0/open-uri.rb:34:in `open'
from test.rb:5:in `<main>'
I can access this from a web browser, I just don't get it at all.
What is going on, and how can I deal with this kind of error? Can I ignore it and let the rest do their work?
You're getting 404 Not Found (OpenURI::HTTPError), so, if you want to allow your code to continue, rescue for that exception. Something like this should work:
require 'nokogiri'
require 'open-uri'
URLS = %w[
http://www.moxyst.com/fashion/men-clothing/underwear.html
]
URLs.each do |url|
begin
doc = Nokogiri::HTML(open(url))
rescue OpenURI::HTTPError => e
puts "Can't access #{ url }"
puts e.message
puts
next
end
puts doc.to_html
end
You can use more generic exceptions, but then you run into problems getting weird output or might handle an unrelated problem in a way that causes more problems, so you'll need to figure out the granularity you need.
You could even sniff either the HTTPd headers, the status of the response, or look at the exception message if you want even more control and want to do something different for a 401 or a 404.
I can access this from a web browser, I just don't get it at all.
Well, that could be something happening on the server side: Perhaps they don't like the UserAgent string you're sending? The OpenURI documentation shows how to change that header:
Additional header fields can be specified by an optional hash argument.
open("http://www.ruby-lang.org/en/",
"User-Agent" => "Ruby/#{RUBY_VERSION}",
"From" => "foo#bar.invalid",
"Referer" => "http://www.ruby-lang.org/") {|f|
# ...
}
You might need to pass 'User-Agent' as parameter to open method. Some sites require a valid User-Agent otherwise they simply don't respond or show a 404 not found error.
doc = Nokogiri::HTML(open("http://www.moxyst.com/fashion/men-clothing/underwear.html", "User-Agent" => "MyCrawlerName (http://mycrawler-url.com)"))
So what is going on and how can I deal with this kind of error.
No clue what's going on, but you can deal with it by catching the error.
begin
doc = Nokogiri::HTML(open("http://www.moxyst.com/fashion/men-clothing/underwear.html"))
puts doc
rescue => e
puts "I failed: #{e}"
end
Can I just ignore it and let the rest do their work?
Sure! Maybe? Not sure. We don't know your requirements.

Sinatra Error Handling in Ruby

I have a simple Sinatra rest and I am having trouble trapping an error. I also admit I am fairly new to Ruby and Sinatra.
When I raise and error in the post endpoint I want to report the incoming document. I need to either 1) handle the error within the post result (where I have access to #incoming) or 2) pass the incoming document to the error and report it there.
What is a better option, option 1 or option 2?
If I stay with option 1, how do I prevent error from picking up the error (as it seems to be doing now)
If I go to option 2, how do I pass incoming to error?
Below is a sample of my code:
post ('/result') do
begin
#incoming = JSON.parse(request.body.read)
//do something that causes an error
rescue
e = env['sinatra.error']
url = request.url
ip = request.ip
#actlogpassblock = { :message => e.message,
:path => url,
:ip => ip,
:timestamp => Time.new,
:type => "500",
:sub => "RES",
:payload => #incoming
}
action_log.insert(#actlogpassblock)
status 500
end
end
error do
status 500
e = env['sinatra.error']
url = request.url
ip = request.ip
backtrace = "Application error\n#{e}\n#{e.backtrace.join("\n")}"
#actlogpassblock = { :message => e.message,
:path => url,
:ip => ip,
:timestamp => Time.new,
:type => "500",
:backtrace => backtrace
}
action_log.insert(#actlogpassblock)
{:result => 'Ah Shucks! Something went wrong'}.to_json
end
If I stay with option 1, how do I prevent error from picking up the
error (as it seems to be doing now)
According to the docs:
The error handler is invoked any time an exception is raised from a
route block...
However, that only applies to uncaught exceptions. Try this:
require 'sinatra'
set :show_exceptions, false
get '/' do
begin
raise ZeroDivisionError
rescue ZeroDivisionError
"rescue clause"
end
end
error do
"sinatra error handler"
end
Then try this:
get '/' do
raise ZeroDivisionError
end
error do
"sinatra error handler"
end
Also, you can tailor the error handler to only catch certain exceptions thereby avoiding some exceptions, e.g.
error IndexError do ...
or
error MyCustomException do ...
or
error 400..510 do
But for the catch all version:
error do
you can't stop that from executing when an uncaught exception occurs in a route block...unless:
The error handlers will only be invoked, however, if both the Sinatra
:raise_errors and :show_exceptions configuration options have been set
to false...
:raise_errors defaults to true in the "test" environment and to false
on other environments.
:show_exceptions value defaults to true in the
"development" environment and to false on other environments
The author of Sintra has said: "This [behavior] is
intentional. The idea is that error blocks will hide the issue and you
usually don't want to do this in development mode.
https://github.com/sul-dlss/sdr-services-app/blob/master/Sinatra-error-handling.md
If I go to option 2, how do I pass incoming to error?
An #variable that is created inside a route block can be seen inside an error block. Try this:
require 'sinatra'
set :show_exceptions, false
get '/' do
#incoming = "hello world" #create #variable
raise ZeroDivisionError
end
error ZeroDivisionError do
#incoming #retrieve #variable
end
After entering the url http://localhost:4567 in your browser, you should see "hello world" on the returned web page.
The reason that works is because an #variable attaches itself to whatever object is self at the time the #variable is created; likewise when an #variable is summoned, it is retrieved from whatever object is self at that time. When Sinatra executes either the route block or the error block it sets self to the same object.
Option 2 seems nice because it separates the error handling code from the application code.

Verifying domain owner

I'm trying to verify whether a user has control of a domain as part of my rails 3 app by uploading a randomly generated file to the root of their domain (the same way google does it for google apps). Currently I'm using Net::HTTP and it seems to work if the address is valid but if the address is not valid I get this error.
getaddrinfo: nodename nor servname provided, or not known
Is there a way to somehow ignore this error or a better/ different way to wrtite the code for the controller?
def check
require 'net/http'
require 'uri'
result = Net::HTTP.get_response(URI.parse('http://www.example.com/21312324213123.html'))
if Net::HTTPSuccess
#test = "true"
else
#test = "false"
end
end
Any help would be great. Thanks.
All you need to do is rescue from that exception and return that as a separate case.
def check
# ...
rescue => e
# Uh oh, got an exception
#error = e.to_s
#test = "false"
end

How do I get the error code and description from a Savon::SOAPFault?

I can see in the Savon log that my SOAP faults contain XML like this:
<errorCode>666</errorCode><errorDescription>some evil error</errorDescription>
Does anyone know how to parse the error code and description out of the response? Sorry if this is a stupid question, but I've tried everything, and I haven't been able to find any documentation on this.
I believe you are looking for this:
def your_method(credentials)
# your client call here
rescue Savon::SOAPFault => error
fault_code = error.to_hash[:fault][:faultcode]
raise CustomError, fault_code
end
Got this solution from Savon documentation.
Thanks!
For the record, the only way I was able to do this was by disabling Savon exceptions:
Savon::Response.raise_errors = false
After doing this, I had to check response.soap_fault? after each SOAP call to see if there was an error. Then I could access the error details using response.to_hash.
I use this patch:
module Savon
class SOAPFault
def soap_error_code
fault = nori.find(to_hash, 'Fault')
if nori.find(fault, 'faultcode')
nori.find(fault, 'faultcode').to_i
elsif nori.find(fault, 'Code')
nori.find(fault, 'Code', 'Value').to_i
end
end
end
end
Then in controller:
begin
# do something
rescue Savon::SOAPFault => e
raise CustomError, e.soap_error_code
end

Check if Internet Connection Exists with Ruby?

Just asked how to check if an internet connection exists using javascript and got some great answers. What's the easiest way to do this in Ruby? In trying to make generated html markup code as clean as possible, I'd like to conditionally render the script tag for javascript files depending on whether or not an internet condition. Something like (this is HAML):
- if internet_connection?
%script{:src => "http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js", :type => "text/javascript"}
- else
%script{:src => "/shared/javascripts/jquery/jquery.js", :type => "text/javascript"}
require 'open-uri'
def internet_connection?
begin
true if open("http://www.google.com/")
rescue
false
end
end
This is closer to what the OP is looking for. It works in Ruby 1.8 and 1.9. It's a bit cleaner too.
I love how everyone simply assume that googles servers are up. Creds to google.
If you want to know if you have internet without relying on google, then you could use DNS to see if you are able to get a connection.
You can use Ruby DNS Resolv to try to translate a url into an ip address. Works for Ruby version 1.8.6+
So:
#The awesome part: resolv is in the standard library
def has_internet?
require "resolv"
dns_resolver = Resolv::DNS.new()
begin
dns_resolver.getaddress("symbolics.com")#the first domain name ever. Will probably not be removed ever.
return true
rescue Resolv::ResolvError => e
return false
end
end
Hope this helps someone out :)
You can use the Ping class.
require 'resolv-replace'
require 'ping'
def internet_connection?
Ping.pingecho "google.com", 1, 80
end
The method returns true or false and doesn't raise exceptions.
Same basics as in Simone Carletti's answer but compatible with Ruby 2:
# gem install "net-ping"
require "net/ping"
def internet_connection?
Net::Ping::External.new("8.8.8.8").ping?
end
require 'open-uri'
page = "http://www.google.com/"
file_name = "output.txt"
output = File.open(file_name, "a")
begin
web_page = open(page, :proxy_http_basic_authentication => ["http://your.company.proxy:80/", "your_user_name", "your_user_password"])
output.puts "#{Time.now}: connection established - OK !" if web_page
rescue Exception
output.puts "#{Time.now}: Connection failed !"
output.close
ensure
output.close
end
I was trying to find a solution to a problem similar to yours and could not find any. Unfortunately the Ping.pingecho method doesn't work for me for some reason i don't know. I came up with a solution. The latest way to do it using httparty. I wanted this in a module and so did it this way and it works just fine
# gem install httparty
require "httparty"
module Main
def Main.check_net
begin
a = HTTParty.get("https://www.google.com")
if a.length() >= 100
puts "online"
end
rescue SocketError
puts "offline"
end
end
end
include Main
Main.check_net
A socket error to Google might not happen so this method will work
def connected?
!!Socket.getaddrinfo("google.com", "http")
rescue SocketError => e
e.message != 'getaddrinfo: nodename nor servname provided, or not known'
end
Since it uses a hostname the first thing it needs to do is DNS lookup, which causes the exception if there is no internet connection.

Resources