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?

¿Fue útil?

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!

https://github.com/savonrb/savon

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.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top