Quelle est la meilleure façon d'utiliser du savon avec du rubis?
Un de mes clients m'a demandé d'intégrer une API tierce dans leur application Rails. Le seul problème est que L'API utilise SOAP. Ruby a essentiellement laissé tomber le savon en faveur du repos. Ils fournissent un adaptateur Java qui fonctionne apparemment avec le Pont Java-Ruby, mais nous aimerions tout garder dans Ruby, si possible. J'ai regardé dans soap4r, mais il semble avoir une réputation légèrement mauvaise.
Alors, quelle est la meilleure façon d'intégrer les appels SOAP dans une application Rails?
10 réponses
Nous avons utilisé la classe soap/wsdlDriver
intégrée, qui est en fait SOAP4R.
C'est un chien lent, mais vraiment simple. Le SOAP4R que vous obtenez de gems / etc est juste une version mise à jour de la même chose.
Exemple de code:
require 'soap/wsdlDriver'
client = SOAP::WSDLDriverFactory.new( 'http://example.com/service.wsdl' ).create_rpc_driver
result = client.doStuff();
C'est à peu près tout
Nous sommes passés de Handsoap à Savon.
Voici une série d'articles de blog comparant les deux bibliothèques clientes.
Essayez SOAP4R
Et je viens d'en entendre parler sur les Rails Envy Podcast (ep 31):
Je viens de faire fonctionner mes affaires dans les 3 heures en utilisant Savon.
La documentation de démarrage sur la page D'accueil de Savon était vraiment facile à suivre-et correspondait en fait à ce que je voyais (pas toujours le cas)
Kent Sibilev de Datanoise avait également porté la bibliothèque Rails ActionWebService sur Rails 2.1 (et au-dessus). Cela vous permet d'exposer vos propres services SOAP basés sur Ruby. Il dispose même d'un mode échafaudage/test qui vous permet de tester vos services à l'aide d'un navigateur.
J'ai utilisé SOAP dans Ruby quand j'ai dû faire un faux serveur SOAP pour mes tests d'acceptation. Je ne sais pas si c'est la meilleure façon d'aborder le problème, mais cela a fonctionné pour moi.
J'ai utilisé Sinatra gem (j'ai écrit sur la création de points de terminaison moqueurs avec Sinatra ici) pour le serveur et aussi Nokogiri pour les choses XML (SOAP travaille avec XML).
Donc, pour le début, j'ai créé deux fichiers (par exemple config.rb et les réponses.rb) dans lequel j'ai mis le prédéfinies réponses que le serveur SOAP retournera. Dans config.rb j'ai mis le fichier WSDL, mais comme une chaîne.
@@wsdl = '<wsdl:definitions name="StockQuote"
targetNamespace="http://example.com/stockquote.wsdl"
xmlns:tns="http://example.com/stockquote.wsdl"
xmlns:xsd1="http://example.com/stockquote.xsd"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns="http://schemas.xmlsoap.org/wsdl/">
.......
</wsdl:definitions>'
Dans réponses.rb j'ai mis des échantillons pour les réponses que le serveur SOAP retournera pour différents scénarios.
@@login_failure = "<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<LoginResponse xmlns="http://tempuri.org/">
<LoginResult xmlns:a="http://schemas.datacontract.org/2004/07/WEBMethodsObjects" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<a:Error>Invalid username and password</a:Error>
<a:ObjectInformation i:nil="true"/>
<a:Response>false</a:Response>
</LoginResult>
</LoginResponse>
</s:Body>
</s:Envelope>"
Alors maintenant, laissez-moi vous montrer comment j'ai créé le serveur.
require 'sinatra'
require 'json'
require 'nokogiri'
require_relative 'config/config.rb'
require_relative 'config/responses.rb'
after do
# cors
headers({
"Access-Control-Allow-Origin" => "*",
"Access-Control-Allow-Methods" => "POST",
"Access-Control-Allow-Headers" => "content-type",
})
# json
content_type :json
end
#when accessing the /HaWebMethods route the server will return either the WSDL file, either and XSD (I don't know exactly how to explain this but it is a WSDL dependency)
get "/HAWebMethods/" do
case request.query_string
when 'xsd=xsd0'
status 200
body = @@xsd0
when 'wsdl'
status 200
body = @@wsdl
end
end
post '/HAWebMethods/soap' do
request_payload = request.body.read
request_payload = Nokogiri::XML request_payload
request_payload.remove_namespaces!
if request_payload.css('Body').text != ''
if request_payload.css('Login').text != ''
if request_payload.css('email').text == some username && request_payload.css('password').text == some password
status 200
body = @@login_success
else
status 200
body = @@login_failure
end
end
end
end
J'espère que vous trouverez cela utile!
J'avais le même problème, je suis passé à Savon et je l'ai juste testé sur un WSDL ouvert (j'ai utilisé http://www.webservicex.net/geoipservice.asmx?WSDL ) et jusqu'à présent tout va bien!
J'ai utilisé un appel HTTP comme ci-dessous pour appeler une méthode SOAP,
require 'net/http'
class MyHelper
def initialize(server, port, username, password)
@server = server
@port = port
@username = username
@password = password
puts "Initialised My Helper using #{@server}:#{@port} username=#{@username}"
end
def post_job(job_name)
puts "Posting job #{job_name} to update order service"
job_xml ="<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:ns=\"http://test.com/Test/CreateUpdateOrders/1.0\">
<soapenv:Header/>
<soapenv:Body>
<ns:CreateTestUpdateOrdersReq>
<ContractGroup>ITE2</ContractGroup>
<ProductID>topo</ProductID>
<PublicationReference>#{job_name}</PublicationReference>
</ns:CreateTestUpdateOrdersReq>
</soapenv:Body>
</soapenv:Envelope>"
@http = Net::HTTP.new(@server, @port)
puts "server: " + @server + "port : " + @port
request = Net::HTTP::Post.new(('/XISOAPAdapter/MessageServlet?/Test/CreateUpdateOrders/1.0'), initheader = {'Content-Type' => 'text/xml'})
request.basic_auth(@username, @password)
request.body = job_xml
response = @http.request(request)
puts "request was made to server " + @server
validate_response(response, "post_job_to_pega_updateorder job", '200')
end
private
def validate_response(response, operation, required_code)
if response.code != required_code
raise "#{operation} operation failed. Response was [#{response.inspect} #{response.to_hash.inspect} #{response.body}]"
end
end
end
/*
test = MyHelper.new("mysvr.test.test.com","8102","myusername","mypassword")
test.post_job("test_201601281419")
*/
J'espère que ça aide. Acclamation.