Sending and Receiving XML using http post - ruby-on-rails

I am new to rails and looking someone to point me in the right direction in how to accomplish the following:-
I need to communicate with an external api by either passing an XML document directly
into the cgi (https://api.domain.com/v1/method.cgi) and set the content-type to
"text/xml", or pass it as a parameter and set the content-type to "text/plain"
I supposedly get an XML response back instead of the HTML response, so no need to
download the HTML response, store it, then render a local copy for the user; nor will
i need to stick the XML document within a parameter of a locally generated HTML form
to submit it via the browser to avoid downloading the HTML.
Each API method has example xml code for (Sending, The Response, DTD, Schema)
What is the best tools/techniques to accomplish this !??
One of their simpler methods is as follows :-
**SEND**
<?xml version="1.0" encoding="utf-8" ?>
<SoftwareAPI>
<Method>ListUsers</Method>
<APIKey>123</APIKey>
<Account>
<UserName>admin</UserName>
<Password>Password</Password>
</Account>
</SoftwareAPI>
**RESPONSE**
<?xml version="1.0" encoding="utf-8" ?>
<SoftwareAPIResponse>
<TimeNow>2012-01-23T16:44:00Z</TimeNow>
<ResponseId>01-23-1232729040-23456</ResponseId>
<ListUsersResponse>
<User>
<Team>team</Team>
<Office>office</Office>
<UserName>Joe.Bloggs</UserName>
<Password>Password123</Password>
<FullName>Joe Bloggs</FullName>
<Language>Auto-Detect</Language>
<Telephone>+44 207 123 456 789</Telephone>
<ResponseEmail>joebloggs#domain.co.uk</ResponseEmail>
</User>
</ListUsersResponse>
</SoftwareAPIResponse>
This API method needs no interaction from the user or view, should the coding be done
from the controller or should I create a model for all the api methods ?
How do I perform a post to the cgi url with the specified XML above and process the
response XML and display in a view ?
What are the best practices for accomplishing this ?
Many Thanks in Advance
Jonny

You guessed it: the best place for your API client is a model. Using a library such as HTTParty or RestClient, this task is fairly easy. The controller should do no more than request the data needed for the view.
Here's some sample code using HTTParty. Since I don't have the details, you'll have to modify it a bit. This would be a model:
class JonnyService
include HTTParty
base_uri 'http://localhost:3000'
end
Then you can use it like this. Note that it might be better to move some of this logic (e.g. creation of the post params for each service method) into the model as class methods for additional convenience.
options = {
:body => {
:SoftwareAPI => {
:Method => 'ListUsers',
:APIKey => '123',
:Account => {
:UserName => 'admin',
:Password => 'password'
}
}
}
}
response = JonnyService.post('/service.xml', options)
puts response.inspect
#response can be treated as a data structure:
puts response['ResponseId']

Related

Rails and XML requests

In my Rails 4 app I am dealing with an API that only handles XML (yes I wish it was JSON too).
I have to make a POST request and the XML string should be stored in a parameter called xmlRequestString.
The XML structure for the POST data is:
<?xml version="1.0" encoding="UTF-8"?>
<GetProperties>
<Auth>
<VendorId>UserID</ VendorId>
<VendorPassword>Password</VendorPassword>
</Auth>
</GetProperties>
As I have never even touched XML before could someone show me how I would actually post this data.
Would something like this be a good way of going about it (borrowed from here: Submitting POST data from the controller in rails to another website)?
require "uri"
require "net/http"
xml = 'xml string can go here'
params = {'xmlRequestString' => xml}
Net::HTTP.post_form(URI.parse('urlendpoint'),params)
You can save this as a template, with instance variables like in a regular html.erb template. Or, you could have it as a method in a model. Either way, you're using something that takes some dynamic data and returns you a text string, that has the xml in it. Then, in your controller, render out the template, or call the method (if you put it in a model) and post it to the api.
#Template method of generating xml
#app/views/properties/get_properties.rxml
xml.instruct! :xml, :version=>"1.0", :encoding => "UTF-8"
xml.GetProperties do
xml.Auth do
xml.VendorId do
<%= #user_id %>
end
xml.VendorPassword do
<%= #password %>
end
end
end
Then, in a controller, call the api:
#user_id = "foo"
#password = "bar"
xml_string = render :template => "properties/get_properties.rxml", :layout => false
http = Net::HTTP.new("www.the-api-website.com")
response = http.post("/path/to/call/the/api", xml_string)

XML feed into Rails object

I'm doing some work with Adcourier. They send me an xml feed with some job data, i.e. job_title, job_description and so on.
I'd like to provide them with a url in my application, i.e. myapp:3000/job/inbox. When they send their feed to that URL, it takes the data and stores it in my database on a Job object that I already created.
What's the best way to structure this? I'm quite new to MVC and i'm not sure where something like this would fit.
How can I get an action to interpret the XML feed from an external source? I use Nokogiri to handle local XMl documents, but never ones from a feed.
I was thinking about using http://api.rubyonrails.org/classes/ActionDispatch/Request.html#method-i-raw_post to handle the post. Doest anyone any thoughts on this?
In your job controller add a action inbox which gets the correct parameter(s) from the post request and saves them (or whatever you need to do with it).
def inbox
data = Xml::ParseStuff(params[:data])
title = data[:title]
description = data[:description]
if Job.create(:title => title, :description => description)
render :string => "Thanks!"
else
render :string => "Data was not valid :("
end
end
Next set your routes.rb to send posts request for that URL to the correct location
resources :jobs do
collection do
post 'inbox'
end
end
Note I did just made up the xml parse stuff here, just google a bit to find out what would be the best solution/gem for parsing your request.

Create record example for Quickbooks Online and Intuit Anywhere using Ruby and httparty?

Can someone post an example of creating a record in quickbooks online / intuit anywhere, using ruby and httparty?
I am working on an integration to a ruby on rails app using intuit anywhere, and am running into an issue with my POST request when attempting to create a new record. I have been able to successfully retrieve data (customers) using a POST command that doesn't require XML data in the body of the request, but am running into trouble when trying to create new records that have required fields that need to be passed in XML in the body of the request.
I get the same flavor of error in any entity for which I try to create a record for: an invalid or missing required field. It seems to me that the XML in the body (where the data for the required fields is added) is either being ignored (incorrect formatting?) or is not being attached.
I was hoping the someone else familiar with ruby could post an example of a record creation using httparty. If I could see how to correctly pass the XML using httparty, I can fix my problem myself.
I have been using the customer.com example (https://code.intuit.com/integration/viewvc/viewvc.cgi/IntuitAnywhere-Ruby/customer.com/?root=intuitanywhere&system=exsy1003) mostly as posted, with a few irrelevant modifications needed to get it to work in Rails 3.1. I am using the data pull and handling provided in the example, which looks like a pretty standard API wrapper built using httparty.
I am using a pull similar to the one found in the company_controller customers method. Here are two different ways I have tried submitting the XML:
#########################################
#Example 1 - XML
e = #company.intuit_token.post("https://qbo.intuit.com/qbo1/resource/account/v2/#{#company.realm}",
{ :body =>
"<Account xmlns:ns2=\"http://www.intuit.com/sb/cdm/qbo\" xmlns=\"http://www.intuit.com/sb/cdm/v2\">
<Name>Test Account 2</Name>
<Desc>Test Account</Desc>
<Subtype>Savings</Subtype>
<AcctNum>5001</AcctNum>
<OpeningBalanceDate>2010-05-14</OpeningBalanceDate>
</Account>",
:headers => {
"Content-Type" => "application/xml"
}}
)
#########################################
#Example 2 - hash
e = #company.intuit_token.post("https://qbo.intuit.com/qbo1/resource/account/v2/#{#company.realm}",
{ :body => {
:Account => {
:Name => "Loan Account 2",
:Desc => "Loac Account 2",
:Subtype => "Savings",
:AcctNum => "5001",
:OpeningBalanceDate => "2011-04-22"
}
},
:headers => {
"Content-Type" => "application/xml"
}}
)
I incorrectly assumed the customer.com example provided by intuit was using the httparty gem to make the POST call, so I was using the wrong syntax. They are actually using the OAuth gem's POST call, who's syntax can be found here: http://oauth.rubyforge.org/rdoc/classes/OAuth/AccessToken.html
I also had to modify the headers to get the Intuit Anywhere service to accept the XML body. Here is the code that finally worked for me to create a record in quickbooks online using intuit anywhere:
e = #company.intuit_token.post("https://qbo.intuit.com/qbo1/resource/account/v2/#{#company.realm}", "<Account xmlns:ns2=\"http://www.intuit.com/sb/cdm/qbo\" xmlns=\"http://www.intuit.com/sb/cdm/v2\"><Name>Test Account </Name><Desc>Test Account</Desc><Subtype>Savings</Subtype><AcctNum>5002</AcctNum><OpeningBalanceDate>2010-05-14</OpeningBalanceDate></Account>", {"Content-Type" => "application/xml", "standalone" => "yes", "encoding" => "UTF-8"})

Rails form => URL => JSON => Save params

This is basically what I want to do, with the params given in a form, I want to do a GET/POST request to a site, this site expects an specific URL like http://site.com/user=XXX&size=XXX and it will give me back a JSON, I want to parse/save the data from this JSON into my rails app when the form is submitted.
I am totally lost with this manner, anything would be very appreciated.
Rails Form Data => Build the URL => Do a GET/Post request => Catch JSON => Parse => Save
for rest api you can use activeresource in your application
http://api.rubyonrails.org/classes/ActiveResource/Base.html
if it's something very specific you can use Net::Http to make requests and then parse json to ruby objects by yourself.
Examples of using http://www.rubyinside.com/nethttp-cheat-sheet-2940.html
for decoding json you can use
Json or ActiveSupport::JSON.decode or this https://github.com/flori/json
I guess you want to do a request to another not your site to get the response. So you can install curb gem (the curl wrapper in ruby). Then use it to make the request on another site and parse json with standart RoR tools like Json to hash.
From http://www.rubyinside.com/nethttp-cheat-sheet-2940.html you get you can do the following:
at the top of your file add:
require "net/http"
require "uri"
require 'json'
then in your controller or helper:
#set the uri
uri = URI.parse("http://my.site.com/uri")
#set the post params and get the respons
response = Net::HTTP.post_form(uri, {"first_param" => "my param", "second_param" => "another param"})
#get the json info
data = JSON.parse(response.body)
#set result to an ActiveRecord (maybe there is a better way to do this, I guess it depends on the response you get
#something = Mymodel.new
#something.name = data["name"]
...
#something.save
Hope it helps!

POSTing File Attachments over HTTP via JSON API

I have a model called Book, which has_many :photos (file attachments handled by paperclip).
I'm currently building a client which will communicate with my Rails app through JSON, using Paul Dix's Typhoeus gem, which uses libcurl.
POSTing a new Book object was easy enough. To create a new book record with the title "Hello There" I could do something as simple as this:
require 'rubygems'
require 'json'
require 'typhoeus'
class Remote
include Typhoeus
end
p Remote.post("http://localhost:3000/books.json",
{ :params =>
{ :book => { :title => "Hello There" }}})
My problems begin when I attempt to add the photos to this query. Simply POSTing the file attachments through the HTML form creates a query like this:
Parameters: {"commit"=>"Submit", "action"=>"create", "controller"=>"books", "book"=>{"title"=>"Hello There", "photo_attributes"=>[{"image"=>#<File:/var/folders/1V/1V8Kw+LEHUCKonqJ-dp3oE+++TI/-Tmp-/RackMultipart20090917-3026-i6d6b9-0>}]}}
And so my assumption is I'm looking to recreate the same query in the Remote.post call.
I'm thinking that I'm letting the syntax of the array of hashes within a hash get the best of me. I've been attempting to do variations of what I was expecting would work, which would be something like:
p Remote.post("http://localhost:3000/books.json",
{ :params =>
{ :book => { :title => "Hello There",
:photo_attributes => [{ :image => "/path/to/image/here" }] }}})
But this seems to concatenate into a string what I'm trying to make into a hash, and returns (no matter what I do in the :image => "" hash):
NoMethodError (undefined method `stringify_keys!' for "image/path/to/image/here":String):
But I also don't want to waste too much time figuring out what is wrong with my syntax here if this isn't going to work anyway, so I figured I'd come here.
My question is:
Am I on the right track? If I clear up this syntax to post an array of hashes instead of an oddly concatenated string, should that be enough to pass the images into the Book object?
Or am I approaching this wrong?
Actually, you can't post files over xhr, there a security precaution in javascript that prevents it from handling any files at all. The trick to get around this is to post the file to a hidden iframe, and the iframe does a regular post to the server, avoiding the full page refresh. The technique is detailed in several places, possibly try this one (they are using php, but the principle remains the same, and there is a lengthy discussion which is helpful):
Posting files to a hidden iframe

Resources