Qual é a melhor maneira de usar SOAP com Ruby?

91

Um cliente meu me pediu para integrar uma API de terceiros em seu aplicativo Rails. O único problema é que a API usa SOAP. Ruby basicamente abandonou o SOAP em favor do REST. Eles fornecem um adaptador Java que aparentemente funciona com a ponte Java-Ruby, mas gostaríamos de manter tudo em Ruby, se possível. Eu pesquisei o soap4r, mas parece ter uma reputação um pouco ruim.

Então, qual é a melhor maneira de integrar chamadas SOAP em um aplicativo Rails?

Jcoby
fonte

Respostas:

36

Usamos a soap/wsdlDriverclasse interna, que na verdade é SOAP4R. É um cão lento, mas muito simples. O SOAP4R que você obtém de gems / etc é apenas uma versão atualizada da mesma coisa.

Código de exemplo:

require 'soap/wsdlDriver'

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

É sobre isso

Orion Edwards
fonte
37
Parte do motivo pelo qual isso é "Dog Slow" é que você está criando o proxy sempre que se conecta ao serviço. Você pode evitar esse problema usando wsdl2ruby para construir o proxy permanentemente e, em seguida, chamar o proxy pré-gerado.
Steve Weet de
6
Poderíamos, mas isso significaria instalar wsdl2ruby e assim por diante. Às vezes, Dog Slow é bom :-)
Orion Edwards
1
Se precisar construir classes proxy para Savon, você pode seguir a abordagem do kredmer de construir métodos soap dinamicamente com a ajuda de SoapUI para preencher nomes de métodos e não ter que construir um analisador wsdl customizado :). Em vez de armazenar todos os métodos na memória, você pode gravar em um arquivo, especialmente se tiver toneladas.
Dejan
3
04/2015: Soap4r está morto, o site está fora do ar. Parece que Savon é a escolha comum neste momento.
Puce de
Tenho pesquisado neste espaço e descobri o soap4r-ng, que ainda está sendo mantido github.com/rubyjedi/soap4r
Ghoti
170

Eu construí Savon de fazer interagir com webservices SOAP de via Rubi o mais fácil possível.
Eu recomendo que você dê uma olhada.

rubiii
fonte
5
+1 para savon, não para bater no soap4r - mas eu tive uma experiência muito ruim com ele. Falta de boa documentação e muito complicado.
konung
1
Agradável! O mundo SOAP em ruby ​​melhorou desde a última vez que tive que usar o Soap4R para fazer isso (~ 18 meses atrás)
madlep
algum de vocês pode me ajudar a acertar a API do sabre usando o Savon? Eu tenho um código que salva me fornecendo os métodos usando wsdl do SOAP, mas não consigo enviar a solicitação usando savon no formato xml.
Jai Kumar Rajput
5

Eu também recomendo Savon . Passei muitas horas tentando lidar com Soap4R, sem resultados. Grande falta de funcionalidade, sem doc.

Savon é a resposta para mim.

Bruno Duyé
fonte
3

Acabei de fazer meu material funcionar em 3 horas usando o Savon.

A documentação de primeiros passos na página inicial de Savon foi realmente fácil de seguir - e realmente correspondeu ao que eu estava vendo (nem sempre é o caso)

ChrisW
fonte
2

Kent Sibilev da Datanoise também portou a biblioteca Rails ActionWebService para Rails 2.1 (e acima). Isso permite que você exponha seus próprios serviços SOAP baseados em Ruby. Ele ainda tem um modo de cadafalso / teste que permite que você teste seus serviços usando um navegador.

Philippe Monnet
fonte
2

Eu usei SOAP em Ruby quando tive que fazer um servidor SOAP falso para meus testes de aceitação. Não sei se essa foi a melhor maneira de abordar o problema, mas funcionou para mim.

Eu usei o Sinatra gem (eu escrevi sobre a criação de pontos de extremidade mocking com Sinatra aqui ) para servidor e também Nokogiri para coisas XML (SOAP está trabalhando com XML).

Portanto, para o início, criei dois arquivos (por exemplo, config.rb e responses.rb) nos quais coloquei as respostas predefinidas que o servidor SOAP retornará. Em config.rb coloquei o arquivo WSDL, mas como uma string.

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

Em responses.rb , coloquei exemplos de respostas que o servidor SOAP retornará para diferentes cenários.

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

Agora, deixe-me mostrar como realmente criei o 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 você ache isso útil!

Radu Rosu
fonte
0

Usei uma chamada HTTP como a seguir para chamar um 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 que ajude. Felicidades.

Rajá
fonte