Как лучше всего использовать SOAP с Ruby?

91

Мой клиент попросил меня интегрировать сторонний API в их приложение Rails. Единственная проблема в том, что API использует SOAP. Ruby в основном отказался от SOAP в пользу REST. Они предоставляют адаптер Java, который, по-видимому, работает с мостом Java-Ruby, но мы хотели бы сохранить все это в Ruby, если это возможно. Я посмотрел на soap4r, но, похоже, у него немного плохая репутация.

Итак, как лучше всего интегрировать вызовы SOAP в приложение Rails?

Jcoby
источник

Ответы:

36

Мы использовали встроенный soap/wsdlDriverкласс, который на самом деле является SOAP4R. Это собачья медлительность, но очень простая. SOAP4R, который вы получаете из gems / etc, - это просто обновленная версия того же самого.

Пример кода:

require 'soap/wsdlDriver'

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

Вот об этом

Орион Эдвардс
источник
37
Частично причина, по которой это "медленная собака", заключается в том, что вы создаете прокси каждый раз, когда подключаетесь к службе. Вы можете избежать этой боли, используя wsdl2ruby для постоянной сборки прокси, а затем вызывая предварительно созданный прокси.
Стив Уит,
7
Мы могли бы, но это означало бы установить wsdl2ruby и так далее, и так далее. Иногда собачья медлительность - это нормально :-)
Орион Эдвардс
1
Если вам нужно создать прокси-классы для Savon, вы можете следовать подходу kredmer по созданию мыльных методов на лету с помощью SoapUI для заполнения имен методов и без необходимости создавать собственный парсер wsdl :). Вместо того, чтобы хранить все методы в памяти, вы можете записывать их в файл, особенно если у вас их тонны.
Dejan
3
04/2015: Soap4r мертв, сайт не работает. Кажется, сейчас Савон - самый распространенный выбор.
Puce
Я покопался в этом пространстве и обнаружил soap4r-ng, который все еще поддерживается github.com/rubyjedi/soap4r
Ghoti
170

Я создал Savon, чтобы максимально упростить взаимодействие с веб-службами SOAP через Ruby.
Я рекомендую вам это проверить.

Rubiii
источник
5
+1 для savon, а не для bash soap4r - но у меня был очень плохой опыт с этим. Отсутствие хорошей документации и слишком громоздкий.
konung
1
Ницца! Мир SOAP в ruby ​​улучшился с тех пор, как мне в последний раз приходилось использовать Soap4R для этого (~ 18 месяцев назад)
madlep
может ли кто-нибудь из вас помочь мне использовать saber api с помощью savon? У меня есть код, который предоставляет мне методы, использующие wsdl для SOAP, но я не могу отправить запрос, используя savon в формате xml.
Джай Кумар Раджпут
5

Еще рекомендую Савон . Я провел слишком много часов, пытаясь разобраться с Soap4R, но безрезультатно. Большой недостаток функционала, без док.

Савон - это ответ для меня.

Бруно Дуйе
источник
3

Я только что заставил мои вещи работать в течение 3 часов с помощью Savon.

Документация по началу работы на домашней странице Савона была очень простой для понимания - и фактически соответствовала тому, что я видел (не всегда так)

ChrisW
источник
2

Кент Сибилев из Datanoise также перенес библиотеку Rails ActionWebService на Rails 2.1 (и выше). Это позволяет вам предоставлять свои собственные сервисы SOAP на основе Ruby. У него даже есть режим scaffold / test, который позволяет вам тестировать свои услуги с помощью браузера.

Филипп Моне
источник
2

Я использовал SOAP в Ruby, когда мне приходилось создавать поддельный сервер SOAP для приемочных испытаний. Не знаю, был ли это лучший способ решить проблему, но у меня он сработал.

Я использовал Синатры камень (я писал о создании насмешливых конечных точек с Синатра здесь ) для сервера , а также Nokogiri для XML - файлов (SOAP работает с XML).

Итак, для начала я создал два файла (например, config.rb и response.rb), в которые я поместил предопределенные ответы, которые вернет сервер SOAP. В config.rb я поместил файл WSDL, но в виде строки.

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

В response.rb я поместил образцы ответов, которые сервер SOAP будет возвращать для разных сценариев.

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

Итак, теперь позвольте мне показать вам, как я фактически создал сервер.

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

Надеюсь, вы найдете это полезным!

Раду Рошу
источник
0

Я использовал HTTP-вызов, как показано ниже, для вызова метода 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")
*/

Надеюсь, это поможет. Ура.

Раджа
источник