Как лучше всего использовать SOAP с Ruby?
-
09-06-2019 - |
Вопрос
Мой клиент попросил меня интегрировать сторонний API в их приложение Rails.Единственная проблема заключается в том, что API использует SOAP.Ruby фактически отказалась от SOAP в пользу REST.Они предоставляют Java-адаптер, который, по-видимому, работает с мостом Java-Ruby, но мы хотели бы сохранить все это на Ruby, если это возможно.Я заглянул в soap4r, но, похоже, у него немного плохая репутация.
Итак, каков наилучший способ интегрировать вызовы SOAP в приложение Rails?
Решение
Мы использовали встроенный класс soap / wsdlDriver
, который на самом деле является SOAP4R.
Это собака медленная, но очень простая. SOAP4R, который вы получаете из gems / etc, является просто обновленной версией того же самого.
Пример кода:
require 'soap/wsdlDriver'
client = SOAP::WSDLDriverFactory.new( 'http://example.com/service.wsdl' ).create_rpc_driver
result = client.doStuff();
Вот и все
Другие советы
Я создал Savon , чтобы максимально упростить взаимодействие с веб-сервисами SOAP через Ruby.
Я бы порекомендовал вам проверить это.
Мы переключились с Handsoap на Savon.
Вот серия постов в блоге , в которой сравниваются две клиентские библиотеки.
Я также рекомендую Savon . Я потратил слишком много часов, пытаясь разобраться с Soap4R, но безрезультатно. Большой недостаток функциональности, нет документов.
Савон - ответ для меня.
Попробуй SOAP4R
И я только что услышал об этом в подкасте Rails Envy (ep 31).:
Только через 3 часа мои материалы заработали с помощью Savon.
Документацию по началу работы на домашней странице Savon было действительно легко понять - и фактически соответствовало тому, что я видел (не всегда так)
Кент Сибилев из Datanoise также перенес библиотеку Rails ActionWebService в Rails 2.1 (и выше). Это позволяет вам предоставлять свои собственные сервисы SOAP на основе Ruby. У него даже есть режим scaffold / test, который позволяет вам тестировать ваши сервисы с помощью браузера.
У меня возникла та же проблема, я переключился на Savon, а затем просто протестировал ее на открытом WSDL (я использовал http://www.webservicex.net/geoipservice.asmx?WSDL ) и пока все хорошо!
Я использовал 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
Надеюсь, вы найдете это полезным!
Я использовал 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")
*/
Надеюсь, это поможет. Приветствия.