Qual è il modo migliore per utilizzare SOAP con Ruby?


91

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 mantenerlo tutto in Ruby, se possibile. Ho esaminato soap4r, ma sembra avere una cattiva reputazione.

Allora qual è il modo migliore per integrare le chiamate SOAP in un'app Rails?

Risposte:


36

Abbiamo usato la soap/wsdlDriverclasse incorporata , che in realtà è SOAP4R. È un cane lento, ma davvero semplice. 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


37
Parte del motivo per cui questo è "Dog Slow" è che stai creando il proxy ogni volta che ti connetti al servizio. È possibile evitare questo problema utilizzando wsdl2ruby per creare il proxy in modo permanente e quindi chiamare il proxy pre-generato.
Steve Weet il

6
Potremmo, ma ciò significherebbe installare wsdl2ruby e così via. A volte Dog Slow va bene :-)
Orion Edwards

1
Se hai bisogno di creare classi proxy per Savon, puoi seguire l' approccio di kredmer di costruire metodi soap al volo con l'aiuto di SoapUI per popolare i nomi dei metodi e non dover creare un parser wsdl personalizzato :). Invece di archiviare tutti i metodi in memoria, puoi scrivere su file, specialmente se ne hai molti.
Dejan

3
04/2015: Soap4r è morto, il sito web non funziona. Sembra che Savon sia la scelta comune in questo momento.
Puce

Ho scavato in questo spazio e ho scoperto soap4r-ng, che viene ancora mantenuto github.com/rubyjedi/soap4r
Ghoti

170

Ho creato Savon per rendere l'interazione con i servizi web SOAP tramite Ruby il più semplice possibile.
Ti consiglio di dare un'occhiata.


5
+1 per savon, non per colpire soap4r - ma ho avuto una brutta esperienza con esso. Mancanza di buona documentazione e troppo ingombrante.
konung

1
Bello! Il mondo SOAP in Ruby è migliorato dall'ultima volta che ho dovuto usare Soap4R per farlo (~ 18 mesi fa)
madlep

qualcuno di voi può aiutarmi a colpire sabre api usando savon? Ho un codice che savon mi fornisce i metodi utilizzando wsdl del SOAP ma non riesco a inviare la richiesta utilizzando savon in formato xml.
Jai Kumar Rajput


5

Raccomando anche Savon . Ho passato troppe ore a provare a gestire Soap4R, senza risultati. Grande mancanza di funzionalità, nessun documento.

Savon è la risposta per me.



3

Ho appena fatto funzionare le mie cose entro 3 ore usando Savon.

La documentazione introduttiva sulla homepage di Savon è stata davvero facile da seguire e in realtà corrispondeva a ciò che stavo vedendo (non sempre il caso)


2

Kent Sibilev di Datanoise aveva anche portato la libreria Rails ActionWebService su Rails 2.1 (e superiori). Ciò consente di esporre i propri servizi SOAP basati su Ruby. Ha anche una modalità scaffold / test che ti consente di testare i tuoi servizi utilizzando un browser.


2

Ho usato SOAP in Ruby quando ho dovuto creare un falso server SOAP 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 di Sinatra (ho scritto sulla creazione di endpoint beffardi con Sinatra qui ) per il server e anche per Nokogiri per roba XML (SOAP funziona con XML).

Quindi, per l'inizio ho creato due file (ad esempio config.rb e responses.rb) in cui ho inserito le risposte predefinite che il server SOAP restituirà. In config.rb ho messo il file WSDL, ma come una 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 responses.rb ho messo degli esempi per le 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!



0

Ho usato 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.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.