Jaki jest najlepszy sposób używania SOAP z Rubim?

91

Mój klient poprosił mnie o zintegrowanie zewnętrznego API z jego aplikacją Rails. Jedynym problemem jest to, że API używa protokołu SOAP. Ruby porzucił SOAP na rzecz REST. Dostarczają adapter Java, który najwyraźniej współpracuje z mostkiem Java-Ruby, ale chcielibyśmy, aby wszystko to w języku Ruby, jeśli to możliwe. Zajrzałem do soap4r, ale wygląda na to, że ma nieco złą reputację.

Jaki jest więc najlepszy sposób integracji wywołań SOAP z aplikacją Railsów?

jcoby
źródło

Odpowiedzi:

36

Użyliśmy wbudowanej soap/wsdlDriverklasy, która w rzeczywistości jest SOAP4R. Pies jest powolny, ale naprawdę prosty. SOAP4R, który otrzymujesz z gems / etc, jest po prostu zaktualizowaną wersją tego samego.

Przykładowy kod:

require 'soap/wsdlDriver'

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

O to chodzi

Orion Edwards
źródło
37
Jednym z powodów, dla których jest to „Dog Slow”, jest fakt, że serwer proxy jest tworzony za każdym razem, gdy łączysz się z usługą. Możesz uniknąć tego problemu, używając narzędzia wsdl2ruby do trwałego zbudowania serwera proxy, a następnie wywołaj wstępnie wygenerowany serwer proxy.
Steve Weet
7
Moglibyśmy, ale oznaczałoby to zainstalowanie wsdl2ruby i tak dalej i tak dalej. Czasami Dog Slow jest w porządku :-)
Orion Edwards
1
Jeśli potrzebujesz zbudować klasy proxy dla Savon, możesz zastosować podejście firmy kredmer do budowania metod mydlanych w locie za pomocą SoapUI, aby zapełniać nazwy metod bez konieczności budowania własnego parsera wsdl :). Zamiast przechowywać wszystkie metody w pamięci, możesz zapisać do pliku, zwłaszcza jeśli masz tony.
Dejan,
3
04/2015: Soap4r nie żyje, witryna nie działa. Wygląda na to, że w tej chwili powszechnym wyborem jest Savon.
Puce
Szperałem w tej przestrzeni i odkryłem soap4r-ng, które wciąż jest utrzymywane github.com/rubyjedi/soap4r
Ghoti
170

Zbudowałem Savon, aby interakcja z usługami sieciowymi SOAP przez Ruby była tak łatwa, jak to tylko możliwe.
Polecam to sprawdzić.

rubiii
źródło
5
+1 za savon, a nie bash soap4r - ale miałem z tym naprawdę złe doświadczenia. Brak dobrej dokumentacji i zbyt kłopotliwe.
konung
1
Ładny! Świat SOAP w Ruby poprawił się od czasu, gdy ostatnio musiałem używać Soap4R, aby to zrobić (~ 18 miesięcy temu)
madlep
czy ktoś z was może mi pomóc w uderzeniu szabli api za pomocą savona? Mam kod, który savon dostarcza mi metody używające wsdl z SOAP, ale nie mogę wysłać żądania przy użyciu savon w formacie xml.
Jai Kumar Rajput
5

Polecam również Savon . Spędziłem zbyt wiele godzin próbując poradzić sobie z Soap4R, bez rezultatów. Duży brak funkcjonalności, brak dokumentu.

Savon jest odpowiedzią dla mnie.

Bruno Duyé
źródło
3

Właśnie sprawiłem, że moje rzeczy działają w ciągu 3 godzin przy użyciu Savon.

Dokumentacja Getting Started na stronie głównej Savona była naprawdę łatwa do naśladowania - i faktycznie pasowała do tego, co widziałem (nie zawsze tak)

ChrisW
źródło
2

Kent Sibilev z Datanoise również przeportował bibliotekę Rails ActionWebService na Rails 2.1 (i nowsze). Pozwala to na udostępnienie własnych usług SOAP opartych na Ruby. Ma nawet tryb scaffold / test, który umożliwia testowanie usług za pomocą przeglądarki.

Philippe Monnet
źródło
2

Użyłem SOAP w Rubim, kiedy musiałem zrobić fałszywy serwer SOAP do moich testów akceptacyjnych. Nie wiem, czy to był najlepszy sposób podejścia do problemu, ale zadziałało.

Użyłem klejnotu Sinatra (pisałem o tworzeniu fałszywych punktów końcowych z Sinatrą tutaj ) dla serwera, a także Nokogiri do obsługi XML (SOAP działa z XML).

Na początek utworzyłem więc dwa pliki (np. Config.rb i responses.rb), w których umieściłem predefiniowane odpowiedzi, które zwróci serwer SOAP. W config.rb umieściłem plik WSDL, ale jako napis.

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

W responses.rb umieściłem próbki odpowiedzi, które serwer SOAP będzie zwracał dla różnych scenariuszy.

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

Pozwólcie, że teraz pokażę, jak właściwie utworzyłem serwer.

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

Mam nadzieję, że okaże się to pomocne!

Radu Rosu
źródło
0

Użyłem wywołania HTTP, jak poniżej, aby wywołać metodę 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")
*/

Mam nadzieję, że to pomoże. Twoje zdrowie.

Radża
źródło