SOAP (Simple Object Access Protocol) é um protocolo baseado em XML para troca de informações em aplicações distribuídas, rodando diferentes sistemas operacionais, com diferentes tecnologias e linguagens.

Why SOAP?
A better way to communicate between applications is over HTTP,
because HTTP is supported by all Internet browsers and servers.
SOAP was created to accomplish this.

http://www.w3schools.com/webservices/ws_soap_intro.asp

A estrutura do SOAP consiste em três partes

alt text; "SOAP Structure Version"

Envelope: Basicamente define o inicio e o fim da mensagem
Header: É opcional, contém informações como dados para autenticação
Body: Contém as informações da mensagem. Dentro do Body ainda existe um elemento opcional que é o Fault, utilizado para reportar erros.

Para facilitar nosso entendimento de como funciona essa comunicação com o webservice, vamos criar um cenário bem simples onde consultamos o status de processamento de um produto identificado pelo lote_id. Vamos também utilizar a gem Savon.

Para criar a conexão utilizei os seguintes parâmetros:

WSDL: Web Service Description Language, fornece todas as informações do web service, como acessá-lo e os métodos disponíveis;
endpoint: link para o servidor;
wsse_auth: autenticação;
proxy: Por motivos de segurança, o servidor só aceita requisições vindas de um determinado IP e porta;
namespaces: São os namespaces da mensagem, quando um namespace diferente é usado a mensagem é discartada.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
class Product < ActiveRecord::Base

  WSDL_PATH_TO_CONSULT = "#{Rails.root}/public/ConsultarLoteAcumulov1.wsdl"
  PROXY_URL = "http://myserver.com.br:3068"

  def check_status!
    client = Savon.client(
      wsdl: WSDL_PATH_TO_CONSULT,
      endpoint: self.check_status_endpoint,
      wsse_auth: [ ENV["USER"], ENV["PASS"] ],
      proxy: PROXY_URL,
      log: true,
      namespaces: {"xmlns:ebs"=>"http://ebs.SERVER.com.br/v1",
                  "xmlns:ebo"=>"http://ebo.SERVER.com.br/v1"}
      )

    # para saber quais metodos estao disponiveis
    # pry(main)> client.operations
    # => [:consultar_lote_acumulo]
    begin
      response = client.call(:consultar_lote_acumulo, message: check_status_hash)
      # ...
    rescue Savon::SOAPFault => error
      #...
    end
  end

  # É comum existir um endpoint para homologação e um para produção
  def check_status_endpoint
    if Rails.env.production?
      "https://prod.b2b.SERVER.com.br:8443/API/ConsultarLoteAcumuloAPISv1"
    else
      "https://qa.b2b.SERVER.com.br:8443/API/ConsultarLoteAcumuloAPISv1"
    end
  end

  # hash da mensagem que será passada no Body
  def check_status_hash
    {
      "ebs:lote-acumulo" => {
        "ebo:lote" => { "ebo:id-lote" => self.id },
        "ebo:parceiro" => {
          "ebo:dados-cadastrais-pj" => { "ebo:cnpj" => "111111111111111" }
        }
      },
      "ebs:indicador-detalhar-itens" => "false",
      "ebs:propriedades-execucao" => { "ebo:id-interface" => "1" }
    }
  end
end

No Controller teremos algo do tipo

1
2
product = Product.find(params[:id])
response = product.check_status!

Para checar a resposta usamos o método body que retorna o SOAP Body como um hash: alt text; "SOAP Response"

Um software legal para usar enquanto estamos testando é o SoapUI. Basta clicar em Novo Projeto, inserir o arquivo WSDL e ele monta a estrutura do resquest: alt text; "SOAPUI Resquest"

Exemplo do response: alt text; "SOAPUI Response"

Até a próxima :D