parsing a httparty get response in ruby - ruby

I can't figure out how to parse this response. I'm only trying to extract one single count from this.
UPDATE:
How can I parse this XML response?
Here's my API connection information
I'm using Ruby irb, with HTTParty
require 'httparty'
api_key = "6e569b3d-3457-9485-edb2-eccd27272dbf"
secret_key = "MDVkYTQzMDgtOWRiOC04NDULTRkYWUtODQwOTc5ZDFkZTQ3NTZhOG1NWQtNmMzMi0xYjE0LWYMzgtNDc0YzU0MWYxYmUx"
def urlncode(string)
URI.escape(string, Regexp.new("[Generating an API Signature^#{URI::PATTERN::UNRESERVED}]"))
end
salt = rand(10000000000).to_s
hash = OpenSSL::HMAC.digest('sha256', secret_key, salt)
signature = urlncode(Base64.encode64(hash))
# controller / action
api_path = "/Tickets/TicketCount"
url = "http://support.myorganization.org/api/index.php?e=#{api_path}"
response = HTTParty.get("#{url}&apikey=#{api_key}&salt=#{salt}&signature=#{signature}").parsed_response
My response: (truncated)
response = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ticketcount>\n<departments>\n<department id=\"0\">\n<totalitems><![CDATA[11]]></totalitems>\n<lastactivity><![CDATA[1423657406]]></lastactivity>\n<totalunresolveditems><![CDATA[11]]></totalunresolveditems>\n<ticketstatus id=\"1\" lastactivity=\"1423657406\" totalitems=\"6\" />\n<ticketstatus id=\"2\" lastactivity=\"1422566730\" totalitems=\"5\" />\n<tickettype id=\"1\" lastactivity=\"1423657406\" totalitems=\"11\" totalunresolveditems=\"11\" />\n<ownerstaff id=\"0\" lastactivity=\"1423657406\" totalitems=\"7\" totalunresolveditems=\"7\" />\n<ownerstaff id=\"4\" lastactivity=\"1420825202\" totalitems=\"2\" totalunresolveditems=\"2\" />\n<ownerstaff id=\"17\" lastactivity=\"1422452400\" totalitems=\"1\" totalunresolveditems=\"1\" />\n<ownerstaff id=\"26\" lastactivity=\"1422566730\" totalitems=\"1\"
When I try to do:
response['ticket count']
I get this: (which is obviously not all the data included)
irb(main):029:0> data['ticketcount']
=> "ticketcount"

Related

TypeError problem: no implicit conversion in Sinatra + JSON.parse

I'm trying to set up a web hook, following this GitHub tutorial
require 'sinatra'
require 'json'
require 'net/http'
require 'pp'
set :port, 31415
# Descarga las diferencias hechas para un push
post '/' do
push = JSON.parse(request.body.read)
piezas = push["compare"].split("/")
api_url = "/repos/#{piezas[3]}/#{piezas[4]}/compare/#{piezas[6]}"
diff = Net::HTTP.get(URI("https://api.github.com#{api_url}"))
puts diff.class
pp(JSON.parse(diff))
end
diff.class prints:
String
And, as a matter of fact, the last sentence works correctly, printing via pp the structure. However, after printing, it yields the error
[2018-10-25 20:00:23] ERROR TypeError: no implicit conversion of Array into String
It's not referencing any line in the script, but would it be possible that the error would be in the first JSON.parse? Could it be that request.body.read would be an array?
Update I couldn't golf it down to any of the JSON.parse separately. Downloading the hook payload works OK, downloading the JSON from the GitHub API works without a glithc. Somehow it's using them together what does not work.
It's possible the library is treating the response like text. Try adding an Accept header. This worked for me:
request["Accept"] = "application/json"
example:
uri = URI.parse("https://api.github.com")
req = Net::HTTP::Get.new(URI("https://api.github.com/repos/JJ/microservices-broker/compare/d5d39c5db99d...bbbf695d1bf2"))
req["Accept"] = 'application/json'
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
response = http.request(req)
json = JSON.parse(response.body)
json['url']
# or
json = JSON.parse(response.body, symbolize_names: true)
json[:url]
(EDIT:) Also, Using Net::HTTP is really painful. Please checkout these libraries:
https://github.com/lostisland/faraday
https://github.com/octokit/octokit.rb

Ruby HTTP post with session cookie

I'm trying to write a Ruby script to use the API on the image gallery site Piwigo, this requires you to login first with one HTTP post and upload an image with another post.
This is what I've got so far but it doesn't work, just returns a 401 error, can anyone see where I am going wrong?
require 'net/http'
require 'pp'
http = Net::HTTP.new('mydomain.com',80)
path = '/piwigo/ws.php'
data = 'method=pwg.session.login&username=admin&password=password'
resp, data = http.post(path, data, {})
if (resp.code == '200')
cookie = resp.response['set-cookie']
data = 'method=pwg.images.addSimple&image=image.jpg&category=7'
headers = { "Cookie" => cookie }
resp, data = http.post(path, data, headers)
puts resp.code
puts resp.message
end
Which gives this response when run;
$ ruby piwigo.rb
401
Unauthorized
There is a Perl example on their API page which I was trying to convert to Ruby http://piwigo.org/doc/doku.php?id=dev:webapi:pwg.images.addsimple
By using the nice_http gem: https://github.com/MarioRuiz/nice_http
NiceHttp will take care of your cookies so you don't have to do anything
require 'nice_http'
path = '/piwigo/ws.php'
data = '?method=pwg.session.login&username=admin&password=password'
http = NiceHttp.new('http://example.com')
resp = http.get(path+data)
if resp.code == 200
resp = http.post(path)
puts resp.code
puts resp.message
end
Also if you want you can add your own cookies by using http.cookies
You can use a gem called mechanize. It handles cookies transparently.

how to serialize AMF body and send it with Ruby RocketAMF

I am trying to serialized an AMF body and send it with RestClient.post.
From the Charles proxy, I can deserialized my request body and show it as follows:
# s is the raw binary from request body
pp RocketAMF::Envelope.new.populate_from_stream(s).messages
However, I cannot figure it out how to serialize such an object and send it (with RestClient.post) in the body.
You'll want to change the URL it's using, but the below is the correct way to do it.
require 'rubygems'
require 'RocketAMF'
require 'rest-client'
data = [] # whatever data you want
env = RocketAMF::Envelope.new :amf_version => 3
env.messages << RocketAMF::Message.new('BatchController.authenticate_iphone', '/1', data)
res = RestClient.post "http://localhost:9292/amf", env.to_s, :content_type => 'application/x-amf'
puts RocketAMF::Envelope.new.populate_from_stream(res).inspect

Why do I get an "unexpected token" error when parsing JSON using Ruby's json gem?

The JSON object I'm parsing is at http://api.4chan.org/3/catalog.json
Here is my Ruby code:
['open-uri','nokogiri','json'].each{|g| require g}
json_test = File.open('json_test.JSON','r').read
board_cat_body = Nokogiri::HTML(open('http://api.4chan.org/3/catalog.json'))
puts JSON.parse(board_cat_body)
Result (it's very long so I took a part of it out):
C:/Ruby193/lib/ruby/1.9.1/json/common.rb:148:in `parse': 387: unexpected token at '{"no":248019,"sticky":1,"closed":1,"now":"12\/19....
However, if I copy and paste the contents of http://api.4chan.org/3/catalog.json into a local JSON file and parse from that local JSON file, there is no problem.
Does anyone know what I'm doing wrong?
Remove the Nokogiri call. JSON isn't HTML.
['open-uri','json'].each{|g| require g}
json = JSON.parse(open('http://api.4chan.org/3/catalog.json').read)
puts json.inspect
The document you get in board_cat_body is not a JSON doc, it's HTML, as you can see if you print it. So, I propose to download the document this way:
require 'net/http'
require 'json'
url = URI.parse('http://api.4chan.org/3/catalog.json')
req = Net::HTTP::Get.new(url.path)
res = Net::HTTP.start(url.host, url.port) { |http| http.request(req) }
and parse it:
puts JSON.parse(res.body)

Parsing SOAP response using SAVON response.to_hash conversion method

I am having trouble parsing a SOAP response.
Here is my code:
require 'rubygems'
require 'savon'
client = Savon::Client.new "http://1.2.3.4/xyz/abcd/fsds.wsdl"
res = client.query_unpaid_assesments do |soap,wsse|
soap.namespaces["xmlns:SOAP-ENV"] = "http://schemas.xmlsoap.org/soap/envelope/"
soap.namespaces["xmlns:xsi"] = "http://www.w3.org/2001/XMLSchema-instance"
soap.namespaces["xmlns:xsd"] = "http://www.w3.org/2001/XMLSchema"
wsse.username="xyz"
wsse.password="123"
soap.body = {:orderNumber => 111222333 }
end
response = Savon::Response#to_hash
hres = response.to_hash
all_data = hres[:response][:asses_data][:date][:amount][:assesReference][:year][:cusOffCode][:serie][:number][:date][:time]
Here is the error that I am having:
undefined method to_hash for Savon::Response:Class (NoMethodError)
"res" is giving me xml response that I would like to have in hash.
I read previous related questions and they recommending to use response.to_hash , which I did and is throwing the error specified above.
How can i get rid of this error and have my response into hash.
thanks for ur help
I forgot to post the body of the xml response that I would like to parse:
<soapenv:Body>
<response>
<ns203:assesData xmlns:ns203="http://asdfsd.sdfsd.zbc.org">
<ns203:date>2010-09-01</ns203:date>
<ns203:amount>34400</ns203:amount>
<ns203:asesReference>
<ns203:year>2010</ns203:year>
<ns203:cusOffCode>098</ns203:customsOfficeCode>
<ns203:serie>F</ns203:serie>
<ns203:number>524332</ns203:number>
<ns203:date>2010-11-11</ns203:date>
<ns203:time>10:11:103</ns203:time>
</ns203:assesReference>
</ns203:assesData>
</response>
</soapenv:Body>
I believe you need to be trying to #to_hash res itself, the returned Savon::Response object, instead of the Savon::Response class.
So hres = res.to_hash should work.
An example I found (at the end of here: http://blog.nofail.de/2010/01/savon-vs-handsoap-calling-a-service/) should give you the idea.
class SavonBankCode
def self.zip_code(bank_code)
client = Savon::Client.new Shootout.endpoints[:bank_code][:uri]
response = client.get_bank { |soap| soap.body = { "wsdl:blz" => bank_code } }
response.to_hash[:get_bank_response][:details][:plz]
end
end
An alternative would be to parse the result with Nokogiri or similar, meaning you could do something like this:
require 'nokogiri'
response = res.xpath("//ns203:assesData", "ns203" => "http://asdfsd.sdfsd.zbc.org")
date = response.xpath("ns203:date", "ns203" => "http://asdfsd.sdfsd.zbc.org")
amount = response.xpath("ns203:amount", "ns203" => "http://asdfsd.sdfsd.zbc.org")
number = response.xpath("ns203:asesReference/ns203:number", "ns203" => "http://asdfsd.sdfsd.zbc.org")
etc. etc. Ugly as sin of course, but hey it is an (untested or refined) alternative ;)
Good luck!
You can also try response.body.
It returns a hash

Resources