Reputation: 801
I have a class to call geo location api. sample url below with Json response something like this
{ "location": { "lat": 31.0, "lng": 14.0 }, "accuracy": 112.4 }
I want to catch any errors, such as 503, 404 or any other errors that might be caused by error in request object. what is the proper way to this with rescue in ruby. also. if there is any error, can i return a message from the ensure block?
def findlocation
begin
location = httparty.get("https://www.googleapis.com/geolocation/v1/geolocate?key=#{API_KEY}")
rescue
# do something after catching error
ensure
return { "message" : "unable to find location" }
end
end
Upvotes: 0
Views: 2392
Reputation: 102218
In general exceptions should be used for exceptional events. Not regular application flow.
When catching exceptions always be specific and only rescue exceptions that you know what to do with.
begin
pats "hello world"
rescue
nil
end
This example shows a serious flaw in the code in yout question - you created a black hole that swallows the NoMethodError that would have told us that there is a typo in the code. This makes debugging extremely difficult. This anti-pattern is known as Pokémon Exception Handling (Gotta catch em' all).
ensure
just ensures that the code is run no matter if the code raised an exception or not. Its used to for example guarantee that the method closes a file handler that it has opened or rolls back a transaction. Its a really big hammer that should be used very sparingly.
HTTParty does not actually raise exceptions when the response code is a "error" code - because its not an exceptional event. Its a part of normal application flow when dealing with HTTP requests. Shit happens. HTTParty raises exceptions if you can't reach the server at all or you can't even reach the network. Those are exceptional events.
class GeolocationClient
include HTTParty
base_uri "https://www.googleapis.com/geolocation/v1"
format :json
attr_accessor :options
def initialize(api_key:)
@options = {
api_key: api_key
}
end
def geolocate
begin
response = self.class.get("/geolocate", options)
if response.successful?
response
else
logger.info("Geolocation API call was unsuccessful. Status code: #{response.code}")
handle_unsuccessful_request
end
rescue HTTParty::Error => e
logger.warn(e.message)
handle_unsuccessful_request
end
end
private
def handle_unsuccessful_request
{ "message" : "unable to find location" }
end
end
response.successful?
tests if the response is in the 2xx
"happy range". Use a switch statement if you want handle each code or range of codes separately.
Upvotes: 4
Reputation: 1941
there are severals way to handle this. First I want to assume you are using the HTTParty library. If that's the case then you should be calling it as HTTParty and not httparty.
Lets say you want to resuce each individual error you can do
response = HTTParty.get("https://www.googleapis.com/geolocation/v1/geolocate?key=#{API_KEY}")
case response.code
when 503
# do something, Internal Server error
when 404
# do something, Page Not found
when 500...600
# do something, unexpected error
end
However the above cases assumes you were someohow able to talk to the requested url. If in any case you were unable to talk to the server and you want to rescue from a general HTTParty error you can do
def findlocation
begin
response = HTTParty.get("https://www.googleapis.com/geolocation/v1/geolocate?key=#{API_KEY}")
rescue HTTParty::Error => e
# Something is wrong
puts "#{e.message}"
end
ensure
allows you to run a piece of code whether or not an exception occurs. So if you want a piece of code to be executed regardless of whether you were able to talk to the Google API, put that in the ensure block
Upvotes: 2