Rescuing a Net::HTTP timeout & Testing with Rspec - ruby-on-rails

given the following service object:
class GetJSON
def self.call(source)
uri = URI.parse(source)
res = Net::HTTP.get_response(uri)
return unless res.is_a?(Net::HTTPSuccess)
JSON.parse(res.body)
end
end
I am getting some errors when Net::HTTP.get_response(uri) takes too long to respond. If this happens, I'd like the method to return nil.
Does below look okay?
class GetJSON
def self.call(source)
uri = URI.parse(source)
begin
res = Net::HTTP.get_response(uri)
rescue Net::ReadTimeout
return
end
return unless res.is_a?(Net::HTTPSuccess)
JSON.parse(res.body)
end
end
How do I write an RSPEC test for this? (i.e. how can I replicate a timeout?)

You can stub the get_response method and cause it to raise an error:
allow(Net::HTTP).to_receive(:get_response).and_raise(Net::ReadTimeout)
This is described in more detail in the RSpec docs.

Related

How to print an api response which can be either JSON or non-JSON in rails?

I have a method which outputs api reponse. The response could be either a JSON response or non-JSON response. For JSON response, my code is as follows:
def process
if success?
JSON.parse(response.body)
else
handle_failure
end
end
And for non-JSON response, I used 'eval' as:
def process
if success?
eval(response.body)
else
handle_failure
end
end
But since response could be anything, how can I make sure that it prints the response in both case?
Thanks
Using the method from Checking if a string is valid json before trying to parse it?, define a method to check if the body is a JSON or not:
def valid_json?(json)
JSON.parse(json)
return true
rescue JSON::ParserError => e
return false
end
In your class above you can then do:
def process
valid_json?(response.body) ? process_json : process_non_json
end
def valid_json?(json)
JSON.parse(json)
return true
rescue JSON::ParserError => e
return false
end
def process_json
if success?
JSON.parse(response.body)
else
handle_failure
end
end
def process_non_json
if success?
eval(response.body)
else
handle_failure
end
end

timeout handling in rails api client

I 'm trying to build a Rails API client. There is an api where I can receive my data as json, which works great so far.
Now I am trying to do some timeout handling but I don't know how. I mean literally. How should I even use timeout handling?
I saw something in a tutorial which I translated for my used gem "net/http" but I cannot imagine that this has even any effect.
Here is my controller code:
require 'net/http'
class OverviewController < ApplicationController
def api_key
ENV["API_KEY"]
end
def handle_timeouts
begin
yield
rescue Net::OpenTimeout, Net::ReadTimeout
{}
end
end
def index
handle_timeouts do
url = "https://example.com/api/#{ api_key }"
uri = URI(url)
response = Net::HTTP.get(uri)
#url_debug = url
#my_hash = response
end
end
end

How to return a value without `return`

How can I return without return like devise's authenticate! method does?
class GroupsController < ApplicationController
def create
authenticate! # After here, the code below will not be excuted.
#group = Group.create(group_params)
redirect_to groups_path
end
end
I am wondering how to do this.
The devise authenticate! doesn't return on failure, it actually throw exceptions if the user isn't authenticated. The exception will get propagated all through the call chain, until it hits a matched rescue statement. The Rails framework is smart enough that it will rescue this kind of exception and convert specific exceptions to the corresponding HTTP status code, for example, ActiveRecord::RecordNotFound will be converted to 404.
This is common programming tricks to return from deep call hierarchy.
def a
raise "ha"
end
def b
puts "calling a"
a
not executed
end
def c
b rescue nil
end
c #=> calling a
And ruby provides catch/throw which serve for this kind of deeper jump.
catch(:ret) do
(1..5).each do |i|
(1..5).each do |j|
puts i * j
throw :ret if i * j > 3
end
end
end
Are you just asking how to return without using the keyword 'return'?
Ruby will automatically return the result from the last line in the method, if thats what you mean. but it would be the same as using the keyword 'return'.

If open-uri works, why does net/http return an empty string?

I am attempting to download a page from Wikipedia. For such a task, I am using gems. When using net/http, all I get is an empty string. So I tried with open-uri and it works fine.
Nevertheless, I prefer the first option because it gives me a much more explicit control; but why is it returning an empty string?
class Downloader
attr_accessor :entry, :url, :page
def initialize
# require 'net/http'
require 'open-uri'
end
def getEntry
print "Article name? "
#entry = gets.chomp
end
def getURL(entry)
if entry.include?(" ")
#url = "http://en.wikipedia.org/wiki/" + entry.gsub!(/\s/, "_")
else
#url = "http://en.wikipedia.org/wiki/" + entry
end
#url.downcase!
end
def getPage(url)
=begin THIS FAULTY SOLUTION RETURNS AN EMPTY STRING ???
connector = URI.parse(url)
connection = Net::HTTP.start(connector.host, connector.port) do |http|
http.get(connector.path)
end
puts "Body:"
#page = connection.body
=end
#page = open(url).read
end
end
test = Downloader.new
test.getEntry
test.getURL(test.entry)
test.getPage(test.url)
puts test.page
P.S.: I am an autodidact programmer so the code might not fit good practices. My apologies.
Because your request return 301 Redirect (check connection.code value), you should follow redirect manually if you are using net/http. Here is more details.

net/http hanging requests causing failure - RoR

I have a bit of code that checks the response code of a list of URL's and presents them back - I am having trouble with a few of URL's that are hanging which causes the application not load at all. How can I make the request to give up after 30 seconds and check the next URL marking the skipped URL as failure.
below is my current code;
(Model/status.rb)
require "net/http"
require "uri"
class Status
def initialize(url)
#url = url
end
def get_status
response.code
end
def active?
["200","203","302"].include?(get_status) ? true : false
end
private
def lookup
URI.parse(#url)
end
def http
Net::HTTP.new(lookup.host, lookup.port)
end
def request
Net::HTTP::Get.new(lookup.request_uri)
end
def response
http.request(request)
end
end
(controllers/welcome_controller.rb)
class WelcomeController < ApplicationController
def index
#syndication = [
["http://v1.syndication.u01.example.uk/organisations?apikey=bbccdd", "U.INT 01"],
["http://v1.syndication.u02.example.uk/organisations?apikey=bbccdd", "U.INT 02"],
].collect { |url| logger.info("Boom #{url[0]}"); ["#{url[1]} (#{url[0]})", Status.new(url[0]).active?] }
end
end
Got the answer..
adding the following to my "def get_status"
def get_status
begin
response.code
rescue Exception => e
Rails.logger.info("Error #{e}")
end
end
This logged the error and the went to the next URL

Resources