I'm consuming a simple SOAP web service to get a small piece of HTML to be included in a Rails site. Unfortunately, I'm not particularly familiar with SOAP.
I need to call the TopHtml() SOAP method on the endpoint below but I need to also pass an ID number like TopHtml(29).
I'm using the Savon gem and my code looks a little something like:
response = Savon::Client.new('http://www.xxxxxx.xxx/webservices/services.asmx?wsdl').top_html(29)
which works but returns the default response for when an ID number was not provided.
It seems that the ID number is not being passed. Does anyone know how to pass parameters to Savon SOAP requests?
Many thanks,
Tristan
try
response = Savon::Client.new('http://www.xxxxxx.xxx/webservices/services.asmx').top_html { |soap| soap.body = { :id => 29} }
In the interests of time, I ended up preparing the request XML myself which is less than ideal (and almost defeats the purpose of using Savon) but it's the only way I could have the request prepared properly. The XML was provided by the developers of the service.
client = Savon::Client.new 'http://www.xxxxxx.xxx/webservices/services.asmx?wsdl'
response = client.top_html do |soap|
soap.xml = ...long xml here...
end
Yuck but I'm not going to spend anymore time on it.
Related
I'm updating my rest-client gem from 1.8 to 2.0.
On 1.8 it sends an array of params on a get request as my-url?ids=1,2,3,4.
But on 2.0 it uses duplicated keys like my-url?ids=1&ids=2&ids=3. For reasons beyond the context of this question, our back end does NOT support the new multiple keys syntax (ok, it supports it, but we'll have to make a big refactor). So I'd like to know if there's a way to use the 2.0 client version and keep sending get array requests with only one key and separated by comma as before?
Based on the rest-client docs https://github.com/rest-client/rest-client#query-parameters it seems your only option would be to serialize the parameters yourself and add them to the URL as the query string.
If you don't like this behavior and want more control, just serialize params yourself (e.g. with URI.encode_www_form) and add the query string to the URL directly for GET parameters or pass the payload as a string for POST requests.
If you provide some sample code on how you're using the gem, we could help out a bit better with sample answers.
Ok yeah Leo Correa was right, so what I had to do is replace my old code
params = {
partner_key: #partner,
resources: ["front_end_config", "gui_settings"]
}
#response = JSON.parse( RestClient.get( "#{api_base_uri}/partner_config.json", params: params.merge({multipart:true}) ) )
with this new one, serializing and encoding by myself...
params = {
partner_key: #partner,
resources: '["front_end_config", "gui_settings"]'
}
params = URI.encode_www_form(params.merge({multipart:true}))
#response = JSON.parse( RestClient.get( "#{api_base_uri}/partner_config.json?#{params}" ) )
It's ugly as hell, but it worked for me. If there's some other idea on how to make it better, I'd appreciate.
So, Rails normally handles parsing of incoming Arrays sent via HTTP Post requests (forms), like this:
"Normally Rails ignores duplicate parameter names. If the parameter
name contains an empty set of square brackets [] then they will be
accumulated in an array." - Rails Guides
But when using Net::HTTP.Post to send a Post request to a third party service (API), then it seems this convention of handling arrays in HTTP Post requests is not followed.
This code:
data = {:categories => [one, two, three]}
http = Net::HTTP.new(uri.host, uri.port)
request = Net::HTTP::Post.new(uri.request_uri)
request.set_form_data(data)
response = http.request(request)
Then set_form_data will serialize the Array like this:
categories=one&categories=two&categories=three
And not like this (which I thought was the conventional Rails way):
categories[]=one&categories[]=two&categories[]=three
Why?
I can see that it has to do with the recent implementation of the URI.encode_www_form method that set_form_data uses. But what is the purpose deviating from the conventional Rails way?
And, more importantly, how do I easily modify this to send it in the latter way (without overloading a bunch of inherent Ruby/Rails methods)?
I found out that the solution was as easy as changing the table name:
data = {'categories[]' => [one, two, three]}
It even works if other elements of the data hash are :symbols.
I'd still be curious to find out why Rails makes this "hack" necessary when using the Net::HTTPHeader::set_form_data method, to get Rails' otherwise conventional way of handling arrays in the url parameters.
I am currently developing a Rails app in which I need to dynamically send XML request to an external web service. I've never done this before and I a bit lost.
More precisely I need to send requests to my logistic partner when the status of an order is updated. For instance when an order is confirmed I need to send data such as the customer's address, the pickup address, etc...
I intended to use the XML builder to dynamically generate the request and Net:HTTP or HTTParty to post the request, based on this example.
Is that the right way to do so? How can I generate the XML request outside the controller and then use it in HTTParty or Net:HTTP?
Thanks for your help,
Clem
That method will work just fine.
As for how to get the XML where you need it, just pass it around like any other data. You can use the Builder representation, which will automatically convert to a String as appropriate, or you can pass around a stringified (to_s) version of the Builder object.
If, for example, it makes sense for your model (which we'll call OrderStatus) to generate the XML, and for your controller to post the request:
# Model (order_status.rb)
def to_xml
xml = Builder::XmlMarkup.new
... # Your code here
xml
end
# Controller (order_statuses_controller.rb)
def some_method
#order_status = OrderStatus.find(:some_criteria)
... # Your code here
http = Net::HTTP.new("www.thewebservicedomain.com")
response = http.post("/some/path/here", #order_status.to_xml)
end
You may want to wrap the HTTP calls in a begin/rescue/end block and do something with the response, but otherwise it's all pretty straightforward and simple.
Make XML with Builder, then send it down the wire.
In your case it sounds like you may need to send several different requests as the order evolves; in that case:
Plan out what your possible order states are.
Determine what data needs to be sent for each state.
Decide how to represent that state within your models, so you can send the appropriate request when the state changes.
Where my example uses one method to generate XML, maybe you'll want 5 methods to handle 5 possible order states.
I am using Ruby on Rails 3 and I am trying to implement APIs to retrieve account information from a web service. That is, I would like to connect to a web service that has the Account class and get information from the show action routed at the URI http://<site_name>/accounts/1.
At this time, in the web service accounts_controller.rb file I have:
class AccountsController < ApplicationController
def show
#account = Account.find(params[:id])
respond_to do |format|
format.html
format.js
format.json { render :json => #account.to_json }
end
end
end
Now I need some advice for connecting to the web service. In the client application, I should have a HTTP GET request, but here is my question: What is "the best" approach to connect to a web service making HTTP requests?
This code in the client application works:
url = URI.parse('http://<site_name>/accounts/1.json')
req = Net::HTTP::Get.new(url.path)
res = Net::HTTP.start(url.host, url.port) {|http|
http.request(req)
}
#output = JSON(res.body)["account"]
but, is the above code "the way" to implement APIs?
Is it advisable to use third-party plugins and gems?
Yes, since you're using RESTful routes, they are your basic API. You're also returning structured JSON data easily consumable by an application.
There are other ways to implement a web services API (e.g. SOAP), but this is a good and proper way.
Since it's a web services API, connecting to the correct URL and parsing the response is the way to go on the client side. Though if you need to access many different resources it might be a good idea to create a flexible way of building the request URL.
If you don't need low-level tweak-ability offered by Net::HTTP, instead take a look at using Open-URI, which comes with Ruby. It makes it easy to request a page and receive the body back. Open-URI doesn't have all the bells and whistles but for a lot of what I do it's plenty good.
A simple use looks like:
require 'open-uri'
body = open('http://www.example.com').read
The docs have many other examples.
These are other HTTP clients I like:
HTTPClient
Typhoeus
They are more tweakable and can handle multiple connections at once if that's what you need. For instance, Typhoeus has a suite of simplified calls, similar to Open-URI's. From the docs:
response = Typhoeus::Request.get("http://www.pauldix.net")
response = Typhoeus::Request.head("http://www.pauldix.net")
response = Typhoeus::Request.put("http://localhost:3000/posts/1", :body => "whoo, a body")
response = Typhoeus::Request.post("http://localhost:3000/posts", :params => {:title => "test post", :content => "this is my test"})
response = Typhoeus::Request.delete("http://localhost:3000/posts/1")
HTTPClient has similar shortened methods too.
I'd recommend using Rails' ActiveResource for most cases. Failing that, httparty.
I would use ActiveResource if you just need a simple way to pull in rest-based resources. It's already included in rails and pretty trivial to set up. You just specify a base url and resource name in your ActiveResource subclass and then you can CRUD rest-based resources with an interface similar to that of ActiveRecord.
rest-client is the most popular gem for easily connecting to RESTful web services
I think one of the best solutions out there is the Her gem. It encapsulates restful requests providing objects with active-record like behavior.
I want to access a URL of another website from one of my models, parse some information and send it back to my user. Is this possible?
For example, the user sends me an address through a POST, and I want to validate the information through a third party website (USPS or GMaps)
What methods would I use to create the request and parse the response?
This is not a redirect. I want to open a new request that is transparent from the client.
There are a lot of libraries to handle this such as:
HTTParty on http://github.com/jnunemaker/httparty
Curb on http://curb.rubyforge.org/
Patron on http://github.com/toland/patron
Example using Patron:
sess = Patron::Session.new
sess.timeout = 10
sess.base_url = "http://myserver.com:9900"
sess.headers['User-Agent'] = 'myapp/1.0'
resp = sess.get("/foo/bar")
if resp.status < 400
puts resp.body
end
Each solution has its own way of handling requests and parsing them as well as variations in their API. Look for what fits your needs the best.