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?
ruby-on-rails
ruby
soap
jcoby
źródło
źródło
Zbudowałem Savon, aby interakcja z usługami sieciowymi SOAP przez Ruby była tak łatwa, jak to tylko możliwe.
Polecam to sprawdzić.
źródło
Przeszliśmy z Handsoap na Savon.
Oto seria postów na blogu porównujących dwie biblioteki klienta.
źródło
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.
źródło
Wypróbuj SOAP4R
Właśnie usłyszałem o tym w Rails Envy Podcast (odc. 31):
źródło
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)
źródło
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.
źródło
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!
źródło
Miałem ten sam problem, przełączyłem się na Savon, a następnie po prostu przetestowałem go na otwartym WSDL (użyłem http://www.webservicex.net/geoipservice.asmx?WSDL ) i jak dotąd dobrze!
https://github.com/savonrb/savon
źródło
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.
źródło