How to handle httparty errors rails - ruby-on-rails

I am using some api with httparty gem
I have read this question:
How can I handle errors with HTTParty?
And there are two most upvoted answers how to handle errors
first one using response codes (which does not address connection failures)
response = HTTParty.get('http://twitter.com/statuses/public_timeline.json')
case response.code
when 200
puts "All good!"
when 404
puts "O noes not found!"
when 500...600
puts "ZOMG ERROR #{response.code}"
end
And the second - catching errors.
begin
HTTParty.get('http://google.com')
rescue HTTParty::Error
# don´t do anything / whatever
rescue StandardError
# rescue instances of StandardError,
# i.e. Timeout::Error, SocketError etc
end
So what is the best practice do handle errors?
Do I need to handle connection failures?
Right now I am thinking of combining this two approaches like this:
begin
response = HTTParty.get(url)
case response.code
when 200
# do something
when 404
# show error
end
rescue HTTParty::Error => error
puts error.inspect
rescue => error
puts error.inspect
end
end
Is it a good approach to handle both connection error and response codes?
Or I am being to overcautious?

You definitely want to handle connection errors are they are exceptions outside the normal flow of your code, hence the name exceptions. These exceptions happen when connections timeout, connections are unreachable, etc, and handling them ensures your code is resilient to these types of failures.
As far as response codes, I would highly suggest you handle edge cases, or error response codes, so that your code is aware when there are things such as pages not found or bad requests which don't trigger exceptions.
In any case, it really depends on the code that you're writing and at this point is a matter of opinion but in my opinion and personal coding preference, handling both exceptions and error codes is not being overcautious but rather preventing future failures.

Related

Ruby 2.3 - Adding Timeout error and notification to net:http request

I have a working system to produce errors and send them to be used by Active Admin.
For example in Active admin, for a specific page of our CMS, the page might execute :
url_must_be_accessible("http://www.exmaple.com", field_url_partner, "URL for the partner")
And this uses the code below to send to the Active Admin Editor different type of errors notifications:
module UrlHttpResponseHelper
def url_must_be_accessible(url, target_field, field_name)
if url
url_response_code = get_url_http_response(url).code.to_i
case url_response_code
when -1
# DNS issue; website does not exist;
errors.add(target_field,
"#{field_name}: DNS Problem -> #{url} website does not exist")
when 200
return
when 304
return
else
errors.add(target_field,
"#{field_name}: #{url} sends #{url_response_code} response code")
end
end
end
def get_url_http_response(url)
uri = URI.parse(URI.encode(url))
request = Net::HTTP.get_response(uri)
return request
rescue Errno::ECONNREFUSED, SocketError => e
OpenStruct.new(code: -1)
end
end
In local mode, this worked great! But in production, we're on Heroku and when a request pn Heroku goes beyond 30 seconds like if you try on this link "http://www.exmaple.com", the app crashes with a "H12 error".
I'd like to add to the code above two things
- timeouts: i think i need both read_timeout and open_timeout and that the read_timeout + open_timeout should be < to 30 seconds, with let's take some security , better < 25seconds
if the request is still "going" after 25 seconds, then avoid reaching 30seconds by giving up/dropping the request
and catch this "we dropped the request intentionnally because risk of timeout" by sending a notification to the user. I'd like to use my current system with somehting along the lines of:
rescue Errno::ECONNREFUSED, SocketError => e
OpenStruct.new(code: -7) # = some random number
end
case url_response_code
when -7
errors.add(target_field,
"#{field_name}: We tried to reach #{url} but this takes too long and risks crashing the app. please check the url and try again.")
How can I create a code like -1 but another one to rescue this "timeout"/"drop the request attempt" that I myself enforce.
Tried but nothing works. I don't manage to create the code for catch and drop this request if reaches 25 seconds...
That's not very beautiful solution (see: https://medium.com/#adamhooper/in-ruby-dont-use-timeout-77d9d4e5a001), but I believe you still can use it here, because you only have one thing happening inside opposite to the example in the link, where multiple actions could cause non-obvious behavior:
def get_url_http_response(url)
uri = URI.parse(URI.encode(url))
request = Timeout.timeout(25) { Net::HTTP.get_response(uri) }
return request
rescue Errno::ECONNREFUSED, SocketError => e
OpenStruct.new(code: -1)
rescue Timeout::Error
# return here anything you want
end

How to catch a 500 Internal Server Error in Rails

I have done this tons of times before when fetching things from a database, etc.
For my specific case I am using a 3rd party to connect to a piece of hardware... Anyways, in the case of an error, such as an invalid id obviously, we want to raise a exception or a rescue... but unfortunately I don't know how to raise it because by the time it is hit, it's too late (I think)
Here...
#
# getting params and saving item above...
#
if item.save
device = RubySpark::Device.new("FAKEUNITID800")
device.function("req", "ITEM")
redirect_to controller: 'items', action: 'edit_items'
end
If this was a valid ID, everything would work, and it would take you to the /edit page! But the issue is, with an invalid ID, it just does...
Completed 500 Internal Server Error in 897ms
RubySpark::Device::ApiError - Permission Denied: Invalid Device ID:
I checked out the following tutorials
Rescue StandardError, Not Exception
How to catch 404 and 500 error in Rails?
Dynamic Rails Error Pages
But honestly, they just make me more confused. Maybe I have the wrong approach to this. I always thought that first you make the request, and then you have a fall back case, depending what status (ie. 200, 500, 404) you get... you go from there.
Rails returns an 500 Internal Server Error response because an exception was raised that it does not no how to handle. You can't rescue "500 Internal Server Error" in Rails because it is not an exception - its the framework bailing from an uncaught exception to avoid data loss or unpredictable behavior.
Fortunatly you don't have to. You can just rescue the RubySpark exception:
begin
device = RubySpark::Device.new("FAKEUNITID800")
device.function("req", "ITEM")
rescue RubySpark::Device::ApiError => e
logger.error(e.message)
end
You can also use rescue_from in Rails controllers that wraps the entire action in a before block:
class FooController < ApplicationCotnroller
rescue_from RubySpark::Device::ApiError, with: :do_something
# ...
end

Handle oauth errors with Google Ruby Client?

I'm using Google API Ruby Client (gem 'google-api-client') in a Rails Web app, and I'd like to know how to catch specific errors in the oauth flow. In particular, what should I look for in the rescue statement? Here's the function called by the redirect after the user authorizes:
require 'google/api_client'
def google_auth_finish
begin
client = Google::APIClient.new
client.authorization.client_id = GOOGLE_CLIENT_ID
client.authorization.client_secret = GOOGLE_CLIENT_SECRET
...
rescue ## WHAT GOES HERE TO IDENTIFY THE ERROR?
# Handle the error
logger.info "There was an error."
end
end
Is there a reference somewhere with defined errors? I've searched and can't find it.
I know this was asked years ago, but I literally just encountered this problem and happened upon this question. You were just missing a small part. This worked for me. I am still relatively new, but in my case it prevented the program from breaking and printed out the error message, then the program continued on.
rescue Exception => error
puts "Error #{error}"
end
try theseRaising An Exception

Client Side Validation, disabled_validators = [:uniqueness], returns 500 http status

In my rails4 project I am using the client side validation gem (branch 4-0-beta).
For security reasons I have disabled the uniqueness validation in the config/initializers/client_side_validations.rb file.
ClientSideValidations::Config.disabled_validators = [:uniqueness]
This works fine and when I test in the browser whether a user email exists I get a 500 status no matter if the user exists or not.
http://localhost:3000/validators/uniqueness?case_sensitive=false&id=01&user[email]=tester#mail.com&_=1379052030490
(If uniqueness is not disabled I get a 200 or 404 status response dependent on whether the user is unique or not.)
HTTP Status Code
However I am not sure if I understand correctly the status code defined in middleware.rb:
client_side_validations / lib / client_side_validations / middleware.rb
def call(env)
if matches = /^\/validators\/(\w+)$/.match(env['PATH_INFO'])
if ClientSideValidations::Config.disabled_validators.include?(matches[1].to_sym)
[500, {'Content-Type' => 'application/json', 'Content-Length' => '0'}, ['']]
else
"::ClientSideValidations::Middleware::#{matches[1].camelize}".constantize.new(env).response
end
else
#app.call(env)
end
end
end
My understanding is that status code 500 should be used for server errors ("A generic error message, given when no more specific message is suitable"). However in this case the uniqueness validation is disabled on purpose and I was therefore thinking whether a 403 "Forbidden" or 405 "Method not allowed" would be more appropriate?
The reason why I am not too happy about the 500 status is that Chrome will automatically display a server error message, and since the client_side_validation gem is not raising an exception, which I can catch within rails, I am stuck with Chrome's default server error message for 500 status code.
Any advice on the appropriate status code in this situation or alternative solutions would be cool.

How can I handle errors with HTTParty?

I'm working on a Rails application using HTTParty to make HTTP requests. How can I handle HTTP errors with HTTParty? Specifically, I need to catch HTTP 502 & 503 and other errors like connection refused and timeout errors.
An instance of HTTParty::Response has a code attribute which contains the status code of the HTTP response. It's given as an integer. So, something like this:
response = HTTParty.get('http://twitter.com/statuses/public_timeline.json')
case response.code
when 200
puts "All good!"
when 404
puts "O noes not found!"
when 500...600
puts "ZOMG ERROR #{response.code}"
end
This answer addresses connection failures. If a URL isn´t found the status code won´t help you. Rescue it like this:
begin
HTTParty.get('http://google.com')
rescue HTTParty::Error
# don´t do anything / whatever
rescue StandardError
# rescue instances of StandardError,
# i.e. Timeout::Error, SocketError etc
end
For more information see: this github issue
You can also use such handy predicate methods as ok? or bad_gateway? like this:
response = HTTParty.post(uri, options)
p response.success?
The full list of all the possible responses can be found under Rack::Utils::HTTP_STATUS_CODES constant.

Resources