Was ist der beste Weg, um SOAP mit Ruby zu verwenden?

91

Ein Kunde von mir hat mich gebeten, eine Drittanbieter-API in seine Rails-App zu integrieren. Das einzige Problem ist, dass die API SOAP verwendet. Ruby hat SOAP grundsätzlich zugunsten von REST eingestellt. Sie bieten einen Java-Adapter, der anscheinend mit der Java-Ruby-Bridge funktioniert, aber wir möchten, wenn möglich, alles in Ruby behalten. Ich habe mich mit soap4r befasst, aber es scheint einen etwas schlechten Ruf zu haben.

Wie lassen sich SOAP-Aufrufe am besten in eine Rails-App integrieren?

jcoby
quelle

Antworten:

36

Wir haben die eingebaute soap/wsdlDriverKlasse verwendet, die eigentlich SOAP4R ist. Es ist Hund langsam, aber sehr einfach. Die SOAP4R, die Sie von gems / etc erhalten, ist nur eine aktualisierte Version derselben Sache.

Beispielcode:

require 'soap/wsdlDriver'

client = SOAP::WSDLDriverFactory.new( 'http://example.com/service.wsdl' ).create_rpc_driver
result = client.doStuff();

Das ist alles

Orion Edwards
quelle
37
Ein Grund dafür, dass dies "Dog Slow" ist, ist, dass Sie den Proxy jedes Mal erstellen, wenn Sie eine Verbindung zum Dienst herstellen. Sie können diesen Schmerz vermeiden, indem Sie den Proxy mit wsdl2ruby dauerhaft erstellen und dann den vorgenerierten Proxy aufrufen.
Steve Weet
6
Wir könnten, aber das würde bedeuten, wsdl2ruby zu installieren und so weiter und so fort. Manchmal ist Dog Slow in Ordnung :-)
Orion Edwards
1
Wenn Sie Proxy-Klassen für Savon erstellen müssen , können Sie mit Hilfe von SoapUI den Ansatz von kredmer verfolgen, Seifenmethoden im laufenden Betrieb zu erstellen, um Methodennamen zu füllen, ohne einen benutzerdefinierten wsdl-Parser erstellen zu müssen :). Anstatt alle Methoden im Speicher zu speichern, können Sie in eine Datei schreiben, insbesondere wenn Sie Tonnen haben.
Dejan
3
04/2015: Soap4r ist tot, Website ist ausgefallen. Es scheint, dass Savon in diesem Moment die übliche Wahl ist.
Puce
Ich habe in diesem Raum herumgegraben und soap4r-ng entdeckt, das immer noch gepflegt wird. Github.com/rubyjedi/soap4r
Ghoti
170

Ich habe Savon entwickelt , um die Interaktion mit SOAP-Webservices über Ruby so einfach wie möglich zu gestalten.
Ich würde empfehlen, dass Sie es überprüfen.

rubiii
quelle
5
+1 für Savon, nicht um soap4r zu verprügeln - aber ich hatte wirklich schlechte Erfahrungen damit. Mangel an guter Dokumentation und zu umständlich.
Konung
1
Nett! Die SOAP-Welt in Ruby hat sich verbessert, seit ich das letzte Mal Soap4R verwenden musste (vor ~ 18 Monaten)
madlep
Kann mir bitte einer von euch helfen, Sabre API mit Savon zu schlagen? Ich habe einen Code, der mir die Methoden mit wsdl der SOAP zur Verfügung stellt, aber ich kann die Anfrage nicht mit savon im XML-Format senden.
Jai Kumar Rajput
13

Wir sind von Handsoap zu Savon gewechselt.

Hier ist eine Reihe von Blog-Posts, in denen die beiden Client-Bibliotheken verglichen werden.

Phoet
quelle
5

Ich empfehle auch Savon . Ich habe zu viele Stunden damit verbracht, mit Soap4R umzugehen, ohne Ergebnisse. Großer Mangel an Funktionalität, kein Dokument.

Savon ist die Antwort für mich.

Bruno Duyé
quelle
3

Ich habe gerade meine Sachen innerhalb von 3 Stunden mit Savon zum Laufen gebracht.

Die Dokumentation "Erste Schritte" auf Savons Homepage war wirklich einfach zu befolgen - und stimmte tatsächlich mit dem überein, was ich sah (nicht immer der Fall).

ChrisW
quelle
2

Kent Sibilev von Datanoise hatte auch die Rails ActionWebService-Bibliothek auf Rails 2.1 (und höher) portiert. Auf diese Weise können Sie Ihre eigenen Ruby-basierten SOAP-Dienste verfügbar machen. Er hat sogar einen Gerüst- / Testmodus, mit dem Sie Ihre Dienste mit einem Browser testen können.

Philippe Monnet
quelle
2

Ich habe SOAP in Ruby verwendet, als ich für meine Abnahmetests einen gefälschten SOAP-Server erstellen musste. Ich weiß nicht, ob dies der beste Weg war, um das Problem anzugehen, aber es hat bei mir funktioniert.

Ich habe Sinatra Juwel verwendet (Ich schrieb über spöttischen Schaffung Endpunkte mit Sinatra hier ) für Server und auch Nokogiri für XML Material (SOAP ist die Arbeit mit XML).

Daher habe ich zu Beginn zwei Dateien erstellt (z. B. config.rb und answers.rb), in die ich die vordefinierten Antworten eingefügt habe, die der SOAP-Server zurückgeben wird. In config.rb habe ich die WSDL-Datei aber als String abgelegt.

@@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 answers.rb habe ich Beispiele für Antworten eingefügt, die der SOAP-Server für verschiedene Szenarien zurückgibt.

@@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>"

Lassen Sie mich Ihnen nun zeigen, wie ich den Server tatsächlich erstellt habe.

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

Ich hoffe, Sie finden das hilfreich!

Radu Rosu
quelle
0

Ich habe einen HTTP-Aufruf wie unten verwendet, um eine SOAP-Methode aufzurufen.

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")
*/

Ich hoffe es hilft. Prost.

Raja
quelle