Qual è il modo migliore per utilizzare SOAP con Ruby?
-
09-06-2019 - |
Domanda
Un mio cliente mi ha chiesto di integrare un'API di terze parti nella sua app Rails.L'unico problema è che l'API utilizza SOAP.Ruby ha sostanzialmente abbandonato SOAP a favore di REST.Forniscono un adattatore Java che apparentemente funziona con il bridge Java-Ruby, ma vorremmo mantenere tutto in Ruby, se possibile.Ho esaminato soap4r, ma sembra avere una reputazione leggermente negativa.
Allora qual è il modo migliore per integrare le chiamate SOAP in un'app Rails?
Soluzione
Abbiamo usato il built-in soap/wsdlDriver
classe, che in realtà è SOAP4R.È molto lento, ma davvero semplice.Il SOAP4R che ottieni da gems/etc è solo una versione aggiornata della stessa cosa.
Codice di esempio:
require 'soap/wsdlDriver'
client = SOAP::WSDLDriverFactory.new( 'http://example.com/service.wsdl' ).create_rpc_driver
result = client.doStuff();
Questo è tutto
Altri suggerimenti
ho costruito Savon per rendere l'interazione con i servizi web SOAP tramite Ruby il più semplice possibile.
Ti consiglierei di dargli un'occhiata.
Siamo passati da Handsoap a Savon.
Ecco un serie di post sul blog confrontando le due librerie client.
Lo consiglio anche Savon.Ho passato troppe ore cercando di gestire Soap4R, senza risultati.Grande mancanza di funzionalità, nessun documento.
Savon è la risposta per me.
Tentativo SOAP4R
E ne ho appena sentito parlare sul Podcast di Rails Envy (ep 31):
Ho appena fatto funzionare le mie cose in 3 ore usando Savon.
La documentazione introduttiva sulla home page di Savon è stata davvero facile da seguire e corrispondeva effettivamente a ciò che stavo vedendo (non sempre è così)
Kent Sibilev da Rumore dei dati aveva anche portato la libreria Rails ActionWebService su Rails 2.1 (e versioni successive).Ciò ti consente di esporre i tuoi servizi SOAP basati su Ruby.Ha anche una modalità impalcatura/test che ti consente di testare i tuoi servizi utilizzando un browser.
Stavo riscontrando lo stesso problema, sono passato a Savon e poi l'ho semplicemente testato su un WSDL aperto (ho usato http://www.webservicex.net/geoipservice.asmx?WSDL) Fino a qui, tutto bene!
Ho utilizzato SOAP in Ruby quando ho dovuto creare un server SOAP falso per i miei test di accettazione.Non so se questo fosse il modo migliore per affrontare il problema, ma per me ha funzionato.
Ho usato la gemma Sinatra (ho scritto sulla creazione di endpoint beffardi con Sinatra Qui) per server e anche Nokogiri per materiale XML (SOAP funziona con XML).
Quindi, per l'inizio ho creato due file (ad es.config.rb e risposte.rb) in cui ho inserito le risposte predefinite che il server SOAP restituirà.In config.rb Ho inserito il file WSDL, ma come stringa.
@@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>'
In risposte.rb Ho inserito esempi di risposte che il server SOAP restituirà per diversi scenari.
@@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>"
Quindi ora lascia che ti mostri come ho effettivamente creato il server.
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
Spero che lo troverai utile!
Ho utilizzato la chiamata HTTP come di seguito per chiamare un metodo 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")
*/
Spero che sia d'aiuto.Saluti.