Issue with Sinatra for getting the response for a GET request for a ROR application - ruby-on-rails

I have a ROR application which wants to GET the contents from a URI through the REST mechanism. Although the URI is able to get the response back when the URI is used in the browser or through the curl. But when sent through the ROR application, it gives the following response: { "error": "\n\n\n \n\n\n Sinatra doesn’t know this ditty. \n \n \n Try this:\n get '/works' do\n \"Hello World\"\nend \n \n\n\n", "status": 404 }. Can someone please help what might be the possible reason for getting such issues with the GET request.
def get_result(url, options = { content_type: 'json' })
uri = URI.parse(url) options[:headers] ||= {}
options[:headers]['Host'] = uri.host
conn = faraday_conn(options[:content_type], options)
.....
if options[:data]
response = conn.post url, {}, options[:headers] do |request|
request.body = options[:data]
end
else response = conn.get url, {}, options[:headers]
end

Related

Conditional use of rails cache fetch syntax when response body has error message

Setup
I'm aware of how to do a Rails.exist ? Rails.read : fetch & rails.write but rails has a nice Rails.cache.fetch syntax that will automatically check if the cache key exists and is valid, return that if true, else run through the block and save to the cache.
Examples
For example (long way)
def search(param1)
if Rails.cache.exist?("key", namespace: "example")
response = Rails.cache.read("key", namespace: "example")
else
conn = faraday_helper(url: "search/url")
response = conn.post do |req|
req.body = { key: param1 }
end
Rails.cache.write("key", response, namespace: "example", expires_in: 1.hour) if response.success?
end
response
end
Short hand using fetch syntax
Rails.cache.fetch("key", namespace: "example") do
conn = faraday_helper(url: "search/url")
response = conn.post do |req|
req.body = { key: value }
end
response
end
This nice short hand does the same thing as the long way, except for the if response.success? which is what I'm interested in. If I make a call to this api, and the response is a 400 with a body of {"error": "invalid value for <key>"} the short way will cache that error response, which is no good. Edit for clarity: I do want that response body with the error, but I don't want to cache.
Question
Does anyone know of a way to pass a lambda or something to conditionally cache using the shorthand fetch syntax? I'd rather not have this method return nil when the cache fails because I want that error message in the response body, and deleting the cache if the response isn't a success seems to defeat the purpose of the entire thing (unless it's faster?)
How I've done it using fetch syntax
def search(param1:)
bailed_resp = nil
cached_resp = Rails.cache.fetch("key", namespace: "example", skip_nil: true, expires_in: 1.hour) do
conn = faraday_helper(url: "search/url")
response = conn.post do |req|
req.body = { key: param1 }
end
# Save the response for later and bail on caching unless response.success is true
bailed_resp = response
break unless response.success?
response
end
# If we bailed on the fetch, use the bailed response, otherwise use the new/fetched cache.
cached_resp == nil ? ResponseWrappers::Service.new(bailed_resp) : ResponseWrappers::Service.new(cached_resp)
end
Though this does work, I fail to see how it's any different than the long form syntax, which for reference:
def search(param1:)
if Rails.cache.exist?("key", namespace: "example")
response = Rails.cache.read("key", namespace: "example")
else
conn = faraday_helper(url: "search/url")
response = conn.post do |req|
req.body = { key: param1 }
end
Rails.cache.write("key", response, namespace: "example", expires_in: 1.hour) if response.success?
end
response
end
Is anyone able to give additional information on the differences between the two and/or if it's negligible?
You can just break from this block
Rails.cache.fetch("key", namespace: "example") do
conn = faraday_helper(url: "search/url")
response = conn.post do |req|
req.body = { key: value }
end
break unless response.success?
response
end
In this case nothing will be written by this key for failure response
But if you try to repeat this code and response will be ok, it will be written
If you want to use this construction in some method and need this method to return response, you change it to:
def search
Rails.cache.fetch("key", namespace: "example") do
conn = faraday_helper(url: "search/url")
response = conn.post do |req|
req.body = { key: value }
end
return response unless response.success?
response
end
end
And process result outside the method

Unable to create draft PayPal invoice using v2 API version

I am upgrading PayPal Invoicing feature from v1 to v2 (Because v1 is deprecated) in my Ruby on Rails application.
Since there's no official library/gem supporting v2 invoicing, so I decided to build everything as per this official documentation here: https://developer.paypal.com/docs/api/invoicing/v2.
The flow is like this:
System will get an access-token based on ClientID and ClientSecret
From this access-token, I will be generating a new invoice_number by sending curl request to: https://api.sandbox.paypal.com/v2/invoicing/generate-next-invoice-number
Upon receiving the invoice_number, I am sending curl request to create draft invoice endpoint with all the required data
curl -v -X POST https://api.sandbox.paypal.com/v2/invoicing/invoice
The issue I am facing is with the last point. I am getting 201 created response from create draft invoice endpoint but the endpoint is not returning me the complete invoice object along with Invoice ID.
Here's what I am getting:
"201"
{"rel"=>"self", "href"=>"https://api.sandbox.paypal.com/v2/invoicing/invoices/INV2-Z3K7-Y79X-36EM-ZQX8", "method"=>"GET"}
If you try opening this link, you'll see this:
{
"name":"AUTHENTICATION_FAILURE",
"message":"Authentication failed due to invalid authentication credentials or a missing Authorization header.",
"links": [
{
"href":"https://developer.paypal.com/docs/api/overview/#error",
"rel":"information_link"
}
]
}
Not sure what I am missing here!
Below is the code for reference:
require 'net/http'
require 'uri'
require 'json'
class PaypalInvoice
def initialize order
#order = order
#client_id = ENV['PAYPAL_CLIENT_ID']
#client_secret = ENV['PAYPAL_CLIENT_SECRET']
#base_url = ENV['AD_PP_ENV'] == 'sandbox' ? 'https://api.sandbox.paypal.com' : 'https://api.paypal.com'
#paypal_access_token_identifier = 'paypal_access_token'
#request_id ||= SecureRandom.uuid
end
def create_draft_invoice
raise "Paypal token not found" unless Rails.cache.exist?(#paypal_access_token_identifier)
invoice_number = "#141"
sleep 5
try = 0
uri = URI.parse(#base_url + "/v2/invoicing/invoices")
request = Net::HTTP::Post.new(uri)
request['X-PAYPAL-SANDBOX-EMAIL-ADDRESS'] = ENV['PAYPAL_CLIENT_EMAIL']
request['Authorization'] = "Bearer #{Rails.cache.fetch(#paypal_access_token_identifier)['access_token']}"
request['Content-Type'] = 'application/json'
request['PayPal-Request-Id'] = #request_id.to_s
request.body = JSON.dump({
"detail" => get_detail(invoice_number),
"invoicer" => get_invoicer,
"primary_recipients" => get_primary_recipients,
"items" => items_info,
"configuration" => {
"partial_payment" => {
"allow_partial_payment" => false,
},
"allow_tip" => false,
"tax_calculated_after_discount" => true,
"tax_inclusive" => true
}
})
req_options = {
use_ssl: uri.scheme == "https",
}
response = Net::HTTP.start(uri.host, uri.port, req_options) do |http|
http.request(request)
end
p 'method: create_draft_invoice. response: '
p response.code
p JSON.parse(response.body)
raise "Paypal token expired" if response.code.to_s == '401'
rescue RuntimeError => error
p "#{error.to_s}"
try += 1
access_token_response_status = get_new_access_token
retry if access_token_response_status.to_s == '200' and try <= 1
end
end
This:
{"rel"=>"self", "href"=>"https://api.sandbox.paypal.com/v2/invoicing/invoices/INV2-Z3K7-Y79X-36EM-ZQX8", "method"=>"GET"}
Is the endpoint for an API call, specifically 'Show invoice details': https://developer.paypal.com/docs/api/invoicing/v2/#invoices_get
Loading it in a browser w/o an Authorization: Bearer <Access-Token> header will give an AUTHENTICATION_FAILURE.
There's currently a bug in Sandbox with unconfirmed emails, so make sure your Sandbox emails are confirmed

Construct NET::HTTP header files

I am required to make an http request with a header similar to the one quoted below.
POST /approval HTTP/1.1
Content-Type:text/xml
Content-Length:569
Host:127.0.0.1
Authorization: WSSE realm="SDP", profile="UsernameToken"
X-WSSE: UsernameToken Username="xxxxxxxxxxxxxxx", PasswordDigest=" xxxxxxxxxxxxxxxx", Nonce=" xxxxxxxxxxxxxx", Created="2012-07-26T11:31:26Z"
X-RequestHeader: request ServiceId="xxxxxxxxxxxxx", TransId=" xxxxxxxxxxxxxxxxxxx" , LinkId="xxxxxxxxxx", FA="xxxxxxxxxx"
Cookie: sessionid=default8fcee064690b45faa9f8f6c7e21c5e5a
Msisdn: 861111111
X-HW-Extension: k1=v1;k2=v2
<ns2:preapprovalrequest xmlns:ns2="http://www.xxxxxxxx.com">
<fromfri>ID:2341305205559/MSISDN</fromfri>
<tofri>ID:2341305205559/MSISDN</tofri>
<message>abc</message>
</ns2:preapprovalrequest>
I have attempted to make the Net::HTTP Ruby 2.2.0 library with something similar to this.
url = 'http://xxx.xxx.xxx.xxx:xx/xxx/xxx/approval'
request_xml = "<?xml version='1.0' encoding='UTF-8'?><ns2:approvalrequest xmlns:ns2='http://www.xxxxxxxx.com'><fromfri></fromfri><tofri></tofri><message></message></ns2:approvalrequest>"
uri = URI(url)
req = Net::HTTP::Post.new(uri.path)
req.content_type = 'text/xml'
req['Authorization']['/']="WSSE"
req['Authorization']['realm']= "xxxxx"
req['Authorization']['profile']="xxxxxxxx"
req['X-WSSE']['/']="UsernameToken"
req['X-WSSE']['Username']=""
req['X-WSSE']['PasswordDigest']=""
req['X-WSSE']['Nonce']=""
req['X-WSSE']['Created']=""
req['X-RequestHeader']['/']="request"
req['X-RequestHeader']['ServiceId']=""
req['X-RequestHeader']['TransId']=""
req['X-RequestHeader']['LinkId']=""
req['X-RequestHeader']['FA']=""
req.body = request_xml
response = Net::HTTP.start(uri.hostname, uri.port) {|http|
http.request(req)
}
result = Hash.from_xml(response.body)
However, this throws errors **NoMethodError: undefined method[]=' for nil:NilClass.on the line**req['Authorization']['/']="WSSE"`.Any idea how to construct a proper header file with multiple fields.
you are operating on an empty hash, either merge into it or assign it properly
require 'net/http'
req = Net::HTTP::Post.new('bla')
req.content_type = 'text/xml'
req['Authorization'] = {
'/' => "WSSE",
'realm' => "xxxxx",
'profile' =>"xxxxxxxx",
}
puts req['Authorization'] # => {"/"=>"WSSE", "realm"=>"xxxxx", "profile"=>"xxxxxxxx"}

Error making http request in ruby on rails

I am trying to make an http request to send and sms through kannel using ruby but its not working,what could be the problem with the code in this method. Thanx
require 'net/http'
def self.send_sms( to, from, message)
id = rand(36**8).to_s(36)
uri= URI('http://localhost:13013/cgi-bin/sendsms?')
params = {username: 'skylinesms', password: 'password', from: '#{from}',
text: '#{message}',
'dlr-url': '#{Rails.application.routes.url_helpers.deliver_url(:id => id)}',
'dlr-mask': 3
}
uri.query = URI.encode_www_form(params)
req = Net::HTTP::Get.new(uri.to_s)
res = Net::HTTP.get_response(uri)
res
end

Google Geocoding API HTTP Request denied - Ruby

The following (and other similar) HTTP request to the Google geocoding API comes out correctly when I paste it into my browser
http://maps.googleapis.com/maps/api/geocode/json?address=1600+Amphitheatre+Parkway,+Mountain+View,+CA&sensor=false
And when I do the following in Ruby
url = URI.parse('http://maps.googleapis.com/maps/api/geocode/json?address=1600+Amphitheatre+Parkway,+Mountain+View,+CA&sensor=false')
req = Net::HTTP::Get.new(url.path)
res = Net::HTTP.start(url.host, url.port) {|http|
http.request(req)
}
puts res.body
I get
{
"results" : [],
"status" : "REQUEST_DENIED"
}
This is the same error I get when not setting the "sensor" property for example, but that's not the problem.
Any suggestions?
You need to use #request_uri instead of #path, or your query parameters will not be included:
url = URI.parse('http://maps.googleapis.com/maps/api/geocode/json?address=1600+Amphitheatre+Parkway,+Mountain+View,+CA&sensor=false')
url.path
# => "/maps/api/geocode/json"
url.request_uri
# => "/maps/api/geocode/json?address=1600+Amphitheatre+Parkway,+Mountain+View,+CA&sensor=false"

Resources