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
Related
I'm trying to up receive updates on my Trello model when a change occurs, which I'm using their webhooks for. The problem is that one of the parameter's name is "action", which seems to be overwritten by Rails depending on the value in the Routes.rb. Is there any way to avoid this or do I just have to live with it?
Routes.rb
match "/trello" => "trello_updates#index", via: [:get,:post]
Webhook reponse
Parameters: {"model"=>{...},"action"=>"index"}
You can write a middleware in initializers and update the params coming from trello webhooks. like below -
class TrelloWebhooks
def initialize(app)
#app = app
end
def call(env)
request = Rack::Request.new(env)
trello_action = request.params['action']
request.update_param('trello_action', trello_action)
status, headers, response = #app.call(env)
[status, headers, response]
end
end
Rails.application.config.middleware.use 'TrelloWebhooks'
I had to modify the code from Vishnu, which is the accepted answer to make it work with a post request, so if you have a post request, you need to fetch the params out from the body of the response instead:
class TrelloWebhooks
def initialize(app)
#app = app
end
def call(env)
request = Rack::Request.new(env)
body = JSON.parse(request.body.string)
trello_action = body["action"]
request.update_param('trello_action', trello_action)
status, headers, response = #app.call(env)
[status, headers, response]
end
end
Rails.application.config.middleware.use 'TrelloWebhooks'
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.
I have a Rails application that is set to receive a webhook from WooCommerce. Specifically I am looking for when an order is created. I have tested and verified that it works when I have protect_from_forgery except create. Now I am trying to secure my application by verify the webhook. WooCommerce's documentation states the following secret is passed in the request header:
secret: an optional secret key that is used to generate a HMAC-SHA256 hash of the request body so the receiver can verify authenticity of the web hook
WooCommerce github doc
At the moment I am not sure how I am suppose to verify the request, then act on it. And if the request is not authorized reject it with a 401. Here is what I am trying:
class HooksController < ApplicationController
protect_from_forgery
before_action :restrict_access
def order_created_callback
...
end
private
SHARED_SECRET = 'my_secret_key'
def verify_webhook(data, hmac_header)
digest = OpenSSL::Digest::Digest.new('sha256')
calculated_hmac = Base64.encode64(OpenSSL::HMAC.digest(digest, SHARED_SECRET, data)).strip
calculated_hmac == hmac_header
end
def restrict_access
data = request.body.read
verified = verify_webhook(data, env["X-WC-Webhook-Signature"])
head :unauthorized unless verified
end
end
But so far I have been unsuccessful. Any input would be greatly appreciated. Thanks.
Ok I figured out the issue I was having. In case anyone else is trying to work with WooCommerce web hook it seems my issue was appropriately grabbing the header file of the request to match it against my calculated HMAC.
SHARED_SECRET = "my_secret"
def verify_webhook(data, hmac_header)
hash = OpenSSL::Digest::Digest.new('sha256')
calculated_hmac = Base64.encode64(OpenSSL::HMAC.digest(hash, SHARED_SECRET, data)).strip
Rack::Utils.secure_compare(calculated_hmac, hmac_header)
end
def restrict_access
data = request.body.read
head = request.headers["X-WC-Webhook-Signature"]
verified = verify_webhook(data, head)
if verified
return
else
render nothing: true, status: :unauthorized
end
end
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
This is the error i get:
Bad Request
bad URI `/v1/user/authenticate.json?access_key=1443560867|2.AQBCC2jMKOEzSjnO.3600.1312826400.0-1129666978|VttMJncSU17Br-g38R9eGF5_qCQ'.
The authenticate method:
require 'open-uri'
class UserController < ApplicationController
respond_to :json
def authenticate
file = open(URI.encode("https://graph.facebook.com/me/permissions?access_token=" + params[:access_key]))
facebook = JSON.parse(file.read)
if facebook["data"].present?
#result = "200"
else
#result = "403"
end
respond_with(#result)
end
end
EDIT: SOLVED THE CODE WORKS ON HEROKU... THE PROBLEM IS ON THE LOCALHOST:3000
On Webrick server, simply add following to config/environments/development.rb:
# Allow webrick to accept pipe char in query string
URI::DEFAULT_PARSER = URI::Parser.new(:UNRESERVED => URI::REGEXP::PATTERN::UNRESERVED + '|')