I'm trying to use someone's API to retrieve data. Here's a plain curl GET that works fine:
$ curl -H 'Authorization: Bearer eyJhbGciOiJSUz...' 'https://app.theirsite.com/api/web/call/call-log?q=\{"pageSize":25,"pageIndex":1,"sortBy":"timeConnected","sortDirection":2,"userAccountId":0,"requestorId":0,"companyAccountId":99,"consumerId":null,"ticksSince":636959988000000000,"ticksUntil":636966899990000000,"callStatusId":1\}'
Note the escaped brackets.
I can't get this to work in rails with curb. I've tried various attempts at formatting the parameters following the '?' in the url, but no luck. Here's my last attempt:
params = {"pageSize": 25,
"pageIndex": 1,
"sortBy": "timeConnected",
"sortDirection": 2,
"userAccountId": 0,
"requestorId": 0,
"companyAccountId": 99,
"consumerId": nil,
"ticksSince": 636959988000000000,
"ticksUntil": 636966899990000000,
"callStatusId": 1}
params_str = JSON[params].to_s
params_str.insert( -2, '\\')
response = Curl.get("https://app.theirsite.com/api/web/call/call-log?q=\\" + params_str ) {|curl|
curl.headers['Authorization'] = 'Bearer ' + #saved.token
curl.verbose = true}
The authorization is fine, but their server is responding with a 500 error {"global":["Index was outside the bounds of the array."]}. This is what I was getting with a direct curl command before I figured out I needed the escaped brackets. I haven't figured out how to get curb to provide an output of the complete url before sending. That would be helpful.
Any thoughts.
OK, not an answer, but I finally gave up on curb and switched to Ruby's net/http.
With the params above, it looks like:
uri = URI.parse("https://app.theirsite.com/api/web/call/call-log?q=" + JSON[params])
request = Net::HTTP::Get.new(uri)
request["Authorization"] = 'Bearer ' + #saved.token
req_options = {
use_ssl: uri.scheme == "https",
}
response = Net::HTTP.start(uri.hostname, uri.port, req_options) do |http|
http.request(request)
end
A bit longer, but no escaped characters and now everything works.
Related
I am trying to submit a feed to Walmarts API following this guide and this api documentation
In their guide it says
Send an item feed to Walmart with payload in either XML or JSON format
I am sending this JSON
{
"MPItemFeedHeader":{
"version":"1.0",
"sellingChannel":"mpsetupbymatch",
"locale":"en"
},
"MPItem":[
{
"Item":{
"productIdentifiers":{
"productId":"042666047173",
"productIdType":"UPC"
},
"ShippingWeight":2,
"price":420.69,
"sku":"RICKS-12345"
}
}
]
}
Via a POST request like so:
# Submits a feed to Walmart
# #param feed_data [Hash] data that will be submited with the feed
# #param type [String] Enum: "item" "RETIRE_ITEM" "MP_ITEM" "MP_WFS_ITEM" "MP_ITEM_MATCH" "MP_MAINTENANCE" "SKU_TEMPLATE_MAP" "SHIPPING_OVERRIDES"
def submit_feed(feed_data, type)
# To add a param to a multipart POST request you need to append the params to the URL
endpoint = "https://marketplace.walmartapis.com/v3/feeds?feedType=" + type
headers = self.api_client.headers.with_indifferent_access
uri = URI(endpoint)
request = Net::HTTP::Post.new(uri)
# Add Required Headers
request['Authorization'] = headers["Authorization"]
request['WM_SEC.ACCESS_TOKEN'] = headers["WM_SEC.ACCESS_TOKEN"]
request['WM_QOS.CORRELATION_ID'] = headers["WM_QOS.CORRELATION_ID"]
request['WM_SVC.NAME'] = headers["WM_SVC.NAME"]
request['Accept'] = headers["Accept"]
# Set form wants an array of arrays, basically the first item is the key and the second the value
request.set_form([["file", feed_data]], 'multipart/form-data')
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
end
The feed successfully submits, but when i check the status this is the response:
{
"feedId":"6DCFAA97311140358D6D842488B24333#AQMBCgA",
"feedStatus":"ERROR",
"shipNode":null,
"submittedBy":null,
"feedSubmissionDate":1627595359155,
"ingestionErrors":{
"ingestionError":[
{
"type":"DATA_ERROR",
"code":"ERR_EXT_DATA_0801001",
"field":"IB",
"description":"Unexpected character '{' (code 123) in prolog; expected '\u003c'\n at [row,col {unknown-source}]: [1,1]"
}
]
},
"itemsReceived":0,
"itemsSucceeded":0,
"itemsFailed":0,
"itemsProcessing":0,
"offset":0,
"limit":50,
"itemDetails":{
"itemIngestionStatus":[
]
},
"additionalAttributes":null
}
Judging by the error message
Unexpected character '{' (code 123) in prolog; expected '\u003c'\n at [row,col {unknown-source}]: [1,1]
It seems like they are expecting me to be sending an XML file, i can't figure out what it is i am doing wrong.
They require that the data is sent as multipart so i can't set the Content-Type to application/json
Is there anything i am missing to tell them in the request that the payload is JSON?
I figured it out with the help of this answer on another question.
You are better off referencing this than Walmarts official documentation
You need to submit a post request to the "https://marketplace.walmartapis.com/v3/feeds endpoint appending your type on the url ?feedType=[something]
You need to make sure that your "Content-Type" is "application/json" if you are sending them JSON.
You do not need to send it multipart like the documentation suggests, just send your entire JSON file as the body and it should work correctly.
Here is my new ruby code to get this done:
# Submits a feed to Walmart
# #param feed_data [Hash] data that will be submited with the feed
# #param type [String] Enum: "item" "RETIRE_ITEM" "MP_ITEM" "MP_WFS_ITEM" "MP_ITEM_MATCH" "MP_MAINTENANCE" "SKU_TEMPLATE_MAP" "SHIPPING_OVERRIDES"
def submit_feed(feed_data, type)
# To add a param to a multipart POST request you need to append the params to the URL
endpoint = "https://marketplace.walmartapis.com/v3/feeds?feedType=" + type
uri = URI.parse(endpoint)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.post(uri.path, feed_data, self.api_client.headers)
end
If someone from Walmart is looking at this question, please improve your documentation.
I am trying to implement the Payfort payment gateway with rails app.
But i am getting following response message:
"response_message":"Signature mismatch"
Following is my try:
params = {command: "AUTHORIZATION",
currency: "USD",
access_code: "z7TfXF2xxxxxxxxxxxx",
merchant_identifier: "xoNbjDoq",
merchant_reference: "405",
language: "en",
amount: 250,
token_name: "token_is_here",
expiry_date: "07/2023",
card_number: "5200421234563432",
card_security_code: "417",
card_holder_name: "Abc Xyz",
remember_me: "YES",
return_url: "http://lvh.me:3000/payments/test"}
params = params.except(:card_security_code, :card_number, :expiry_date, :card_holder_name, :remember_me)
params = params.sort.to_h
string = params.to_query(nil)
string = string.gsub! '&', ''
string = ##sha_request + string + ##sha_request
string = Digest::SHA256.hexdigest string
uri = URI.parse("https://sbpaymentservices.payfort.com/FortAPI/paymentApi")
header = {'Content-Type': 'application/json'}
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Post.new(uri.request_uri, header)
request.body = params.to_json
response = http.request(request)
Check sequence of parameters while generating signature. and check for algorithm which u have setup in account and use same algorithm while generating signature
Or else try using their gem
https://github.com/payfort/start-ruby
there may be many reasons for such issue one of them is rails form params and also hashing algorithm, here's my implementation for it
def sign_with_key(params, key)
string_to_digest = params.sort { |a, b| a[0].upcase <=> b[0].upcase }.map { |k, v| "#{k}=#{v}" }.join()
string_to_digest.prepend(key)
string_to_digest << key
"Digest::#{#options[:sha].upcase}".constantize.hexdigest(string_to_digest)
end
Rest of the code seems good but the issue I faced and I see here is that you are using string = params.to_query(nil) which will used escaped characters %20 instead of space in card_holder_name
So I used CGI.unescape and fixed the issue -
def signature(string)
Digest::SHA256.hexdigest(CGI.unescape("#{SHA_REQUEST_PHRASE}#{string.gsub(/&/, "")}#{SHA_REQUEST_PHRASE}"))
end
Hope it helps :)
In Ruby 2.0.0p195, Rails 4.0.0, Net::HTTP::Post.new request returns empty body of response.
#toSend = {
"zuppler_store_id" => 'X3r82l89',
"user_id" => '1'
}.to_json
uri = URI("http://smoothpay.com/zuppler/gen_token_post.php")
http = Net::HTTP.new(uri.host,uri.port)
req = Net::HTTP::Post.new uri
req.content_type = "application/json"
req.body = #toSend # or "[ #{#toSend} ]" ?
res = Net::HTTP.start(uri.host, uri.port) {|http| http.request(req)}
puts "Response #{res.code} - #{res.message}: #{res.body}"
This code returns "Response 200 - OK:"
But it should return like this: {"result":"success","token":"843e5be88fb8cee7d324244929177b4e"}
You can check it by typing this url:
http://smoothpay.com/zuppler/gen_token_test.php
Why is res.body empty?
Seems like that service doesn't like the POST request to be application/json.
This works:
uri = URI("http://smoothpay.com/zuppler/gen_token_post.php")
http = Net::HTTP.new(uri.host,uri.port)
req = Net::HTTP::Post.new uri
req.body = "zuppler_store_id=X3r82l89&user_id=1"
res = Net::HTTP.start(uri.host, uri.port) {|http| http.request(req)}
res.body # => "{\"result\":\"success\",\"token\":\"9502e49d454ab7b7dd2699a26f742cda\"}"
In other words, give the service application/x-www-form-urlencoded. Peculiarly, it will hand you back text/html which you'll have to JSON.parse. Weird service.
We have a Rails 3.2.12 app that fetches data from a partner API by making POST requests. However, we're finding that our code seems to be a bottleneck, as it takes longer to process requests than expected. Can we do anything to speed up the code?
Should we use another XML parser? Is there a faster way to post SSL requests in Ruby?
Thanks!
def ced( ad )
# Set vars
u = 'e'
pw = 'p'
ad = ad.join ','
url = 'https://r.e.com/interface.asp?ResponseType=XML&Command=BC' + '&UID=' + u + '&PW=' + pw + '&DL=' + ad
results = []
# Invoke API command
uri = URI.parse url
http = Net::HTTP.new uri.host, uri.port
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
req = Net::HTTP::Get.new uri.request_uri
resp = http.request req
# Parse API response
resp_xml = Nokogiri.XML resp.body
resp_xml.remove_namespaces!
num_errors = resp_xml.at_xpath('//ErrCount').content
# Any errors?
if num_errors != '0'
error = true
# No errors, process domains
else
resp_xml.xpath('//CheckResult').each do |elem|
results << {
:domain => elem.xpath('D').text.downcase,
:status => case elem.xpath('RRPCode').text
when '210' then 'a'
when '211' then 't'
else
error = true
'error'
end
}
end
end
<truncated>
end
I would like to run the following command in ruby on rails via a proxy:
curl --request POST http://200.206.38.24:8580/my_server_path/
--data-binary #test01.xml
--header "Content-type: Application/vnd.vizrt.payload+xml;type=element"
And so far I have:
PROXY_URL = 'proxy.mydomain.com'
PROXY_PORT = 3128
PROXY_USER = 'user'
PROXY_PASSWORD = 'pass'
MSE_HOST = '200.206.38.24'
MSE_PORT = 8580
MSE_PATH = '/my_server_path/'
xml_file = '<?xml version="1.0" encoding="utf-8"?><etc... />'
Net::HTTP::Proxy(PROXY_URL, PROXY_PORT, PROXY_USER, PROXY_PASSWORD).start(MSE_HOST, MSE_PORT) do |http|
response = http.post(MSE_PATH, xml_file, {"Content-type" => "Application/vnd.vizrt.payload+xml;type=element"})
end
Thanks in advance for any help.
According to tests, it works fine.
The response from http.post can be accessed via the body method. Eg: response.body