Apa cara terbaik menggunakan SOAP dengan Ruby?

91

Seorang klien saya meminta saya untuk mengintegrasikan API pihak ketiga ke dalam aplikasi Rails mereka. Satu-satunya masalah adalah bahwa API menggunakan SOAP. Ruby pada dasarnya menjatuhkan SOAP untuk mendukung REST. Mereka menyediakan adaptor Java yang tampaknya berfungsi dengan bridge Java-Ruby, tetapi kami ingin menyimpan semuanya di Ruby, jika memungkinkan. Saya melihat ke soap4r, tetapi tampaknya memiliki reputasi yang sedikit buruk.

Jadi, apa cara terbaik untuk mengintegrasikan panggilan SOAP ke dalam aplikasi Rails?

jcoby
sumber

Jawaban:

36

Kami menggunakan soap/wsdlDriverkelas bawaan, yang sebenarnya adalah SOAP4R. Anjing itu lambat, tapi sangat sederhana. SOAP4R yang Anda dapatkan dari permata / dll hanyalah versi terbaru dari hal yang sama.

Kode contoh:

require 'soap/wsdlDriver'

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

Itu saja

Orion Edwards
sumber
37
Sebagian alasan mengapa ini disebut "Dog Slow" adalah karena Anda membuat proxy setiap kali Anda tersambung ke layanan. Anda dapat menghindari rasa sakit ini dengan menggunakan wsdl2ruby untuk membangun proxy secara permanen dan kemudian memanggil proxy yang dibuat sebelumnya.
Steve Weet
7
Kami bisa, tapi itu berarti menginstal wsdl2ruby dan seterusnya dan seterusnya. Terkadang Dog Slow baik-baik saja :-)
Orion Edwards
1
Jika Anda perlu membangun kelas proxy untuk Savon, Anda dapat mengikuti pendekatan kredmer untuk membuat metode sabun secara langsung dengan bantuan SoapUI untuk mengisi nama metode dan tidak harus membuat parser wsdl khusus :). Alih-alih menyimpan semua metode dalam memori, Anda dapat menulis ke file, terutama jika Anda punya banyak.
Dejan
3
04/2015: Soap4r mati, situs web mati. Sepertinya Savon adalah pilihan umum saat ini.
Puce
Saya telah menggali di sekitar ruang ini dan menemukan soap4r-ng, yang masih dipertahankan github.com/rubyjedi/soap4r
Ghoti
170

Saya membangun Savon untuk membuat interaksi dengan layanan web SOAP melalui Ruby semudah mungkin.
Saya sarankan Anda memeriksanya.

rubiii
sumber
5
1 untuk savon, bukan untuk menampar soap4r - tetapi saya memiliki pengalaman yang sangat buruk dengannya. Kurangnya dokumentasi yang bagus dan terlalu rumit.
konung
1
Bagus! Dunia SOAP di ruby ​​telah meningkat sejak terakhir kali saya harus menggunakan Soap4R untuk melakukan ini (~ 18 bulan yang lalu)
madlep
bisakah salah satu dari kalian membantu saya untuk memukul api pedang menggunakan savon? Saya memiliki kode yang savon memberi saya metode menggunakan wsdl dari SOAP tetapi saya tidak dapat mengirim permintaan menggunakan savon dalam format xml.
Jai Kumar Rajput
5

Saya juga merekomendasikan Savon . Saya menghabiskan terlalu banyak waktu untuk mencoba menangani Soap4R, tanpa hasil. Kurangnya fungsionalitas, tidak ada dokumen.

Savon adalah jawaban untuk saya.

Bruno Duyé
sumber
3

Baru saja membuat barang-barang saya bekerja dalam 3 jam menggunakan Savon.

Dokumentasi Memulai di beranda Savon sangat mudah diikuti - dan benar-benar cocok dengan apa yang saya lihat (tidak selalu demikian)

ChrisW
sumber
2

Kent Sibilev dari Datanoise juga telah mem-porting library Rails ActionWebService ke Rails 2.1 (dan yang lebih baru). Ini memungkinkan Anda untuk mengekspos layanan SOAP berbasis Ruby Anda sendiri. Dia bahkan memiliki mode perancah / uji yang memungkinkan Anda menguji layanan Anda menggunakan browser.

Philippe Monnet
sumber
2

Saya telah menggunakan SOAP di Ruby ketika saya harus membuat server SOAP palsu untuk tes penerimaan saya. Saya tidak tahu apakah ini cara terbaik untuk mengatasi masalah, tetapi berhasil untuk saya.

Saya telah menggunakan permata Sinatra (saya menulis tentang membuat titik akhir yang mengejek dengan Sinatra di sini ) untuk server dan juga Nokogiri untuk barang XML (SOAP bekerja dengan XML).

Jadi, untuk permulaan saya telah membuat dua file (misalnya config.rb dan respond.rb) di mana saya telah meletakkan jawaban yang telah ditentukan yang akan dikembalikan SOAP server. Di config.rb saya telah meletakkan file WSDL, tetapi sebagai 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>'

Di respond.rb saya telah meletakkan sampel untuk tanggapan bahwa server SOAP akan kembali untuk skenario yang berbeda.

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

Jadi sekarang izinkan saya menunjukkan kepada Anda bagaimana saya sebenarnya membuat 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

Saya harap ini berguna bagi Anda!

Radu Rosu
sumber
0

Saya telah menggunakan panggilan HTTP seperti di bawah ini untuk memanggil metode 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")
*/

Semoga membantu. Bersulang.

Raja
sumber