¿Cuál es la mejor manera de utilizar SOAP con Ruby?
-
09-06-2019 - |
Pregunta
Un cliente mío me pidió que integrara una API de terceros en su aplicación Rails.El único problema es que la API usa SOAP.Básicamente, Ruby abandonó SOAP en favor de REST.Proporcionan un adaptador Java que aparentemente funciona con el puente Java-Ruby, pero nos gustaría mantenerlo todo en Ruby, si es posible.Busqué en Soap4r, pero parece tener una reputación ligeramente mala.
Entonces, ¿cuál es la mejor manera de integrar llamadas SOAP en una aplicación Rails?
Solución
Usamos el incorporado soap/wsdlDriver
clase, que en realidad es SOAP4R.Es lento como un perro, pero realmente simple.El SOAP4R que obtienes de gems/etc es solo una versión actualizada de lo mismo.
Código de ejemplo:
require 'soap/wsdlDriver'
client = SOAP::WSDLDriverFactory.new( 'http://example.com/service.wsdl' ).create_rpc_driver
result = client.doStuff();
Eso es todo
Otros consejos
construí Savón para que la interacción con los servicios web SOAP a través de Ruby sea lo más fácil posible.
Te recomiendo que lo revises.
Cambiamos de Handsoap a Savon.
Aquí hay un serie de publicaciones de blog comparando las dos bibliotecas cliente.
Yo también recomiendo Savón.Pasé demasiadas horas intentando utilizar Soap4R, sin resultados.Gran falta de funcionalidad, sin documento.
Savon es la respuesta para mí.
Intentar SOAP4R
Y acabo de enterarme de esto en el Rails Envy Podcast (ep 31):
Acabo de hacer que mis cosas funcionen en 3 horas usando Savon.
La documentación de introducción en la página de inicio de Savon fue realmente fácil de seguir y, de hecho, coincidía con lo que estaba viendo (no siempre es el caso).
Kent Sibilev de Ruido de datos También había portado la biblioteca Rails ActionWebService a Rails 2.1 (y superior).Esto le permite exponer sus propios servicios SOAP basados en Ruby.Incluso tiene un modo de andamio/prueba que le permite probar sus servicios utilizando un navegador.
Estaba teniendo el mismo problema, cambié a Savon y luego lo probé en un WSDL abierto (usé http://www.webservicex.net/geoipservice.asmx?WSDL) ¡Y hasta ahora todo bien!
Utilicé SOAP en Ruby cuando tuve que crear un servidor SOAP falso para mis pruebas de aceptación.No sé si esta fue la mejor manera de abordar el problema, pero funcionó para mí.
He usado Sinatra gem (escribí sobre la creación de puntos finales simulados con Sinatra aquí) para el servidor y también Nokogiri para cosas XML (SOAP funciona con XML).
Entonces, para empezar, creé dos archivos (p. ej.config.rb y Responses.rb) en el que he puesto las respuestas predefinidas que devolverá el servidor SOAP.En configuración.rb He puesto el archivo WSDL, pero como una cadena.
@@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>'
En respuestas.rb He puesto ejemplos de respuestas que el servidor SOAP devolverá para diferentes escenarios.
@@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>"
Ahora déjenme mostrarles cómo creé realmente el servidor.
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
¡Espero que esto te resulte útil!
He utilizado una llamada HTTP como la siguiente para llamar a un método 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")
*/
Espero eso ayude.Salud.