DEV Community

Marcelo Magario
Marcelo Magario

Posted on • Edited on

Desafio de Integração: Conectando um Backend Node.js a um Web Service SOAP (.ASMX)

Olá pessoal!

Hoje quero compartilhar uma experiência de um projeto recente que envolveu um desafio clássico: fazer o novo conversar com o antigo. Especificamente, como consumir um Web Service baseado em SOAP a partir de uma aplicação moderna escrita em Node.js.

Muitas vezes, precisamos integrar nossas aplicações com sistemas legados de clientes ou parceiros, e entender como criar essa ponte é uma habilidade valiosa.

**O Problema de Negócio: Uma Nova Fonte de Dados

De forma resumida, o cenário era o seguinte:

  • A Plataforma: Nós gerenciamos uma plataforma web para um cliente, com o backend construído em Node.js e servindo uma API REST para o frontend.
  • O Cliente: O cliente, uma grande instituição do setor financeiro, armazena e gerencia seus dados em um sistema interno.
  • A Fonte de Dados: Para nos fornecer os dados, o cliente expõe um Web Service ASP.NET (.ASMX), que é uma tecnologia baseada no protocolo SOAP.
  • A Nova Demanda: O cliente precisava exibir uma nova categoria de produtos em seu site. Para isso, eles criaram um novo método dentro do Web Service existente, e nossa tarefa era consumir esse novo método para alimentar a nova página.

Nosso objetivo era criar um novo endpoint em nossa API Node.js (ex: GET /api/produtos/nova-categoria) que, por debaixo dos panos, chamasse o novo método SOAP do cliente, tratasse os dados e os devolvesse em um formato JSON limpo e moderno para o frontend.

A Solução Técnica: Usando node-soap para a Mágica Acontecer

Para interagir com um serviço SOAP em Node.js, a biblioteca mais popular e robusta é a node-soap. Ela faz o trabalho pesado de analisar o arquivo WSDL (Web Services Description Language) do serviço, permitindo que a gente chame os métodos remotos como se fossem funções JavaScript comuns.

Vamos ao passo a passo da implementação.

Passo 1: Estruturando o Novo Endpoint na API

A primeira parte é simples: definir a rota em nossa aplicação Express.js. Isso expõe um novo caminho que nosso frontend poderá chamar.

// Em algum arquivo de rotas, como 'productRoutes.js'
const express = require('express');
const router = express.Router();

// Importamos nosso "service", que conterá a lógica de negócio
const productService = require('../services/productService');

// Quando uma requisição GET chegar em '/products/new-category', 
// a função fetchNewCategoryData será chamada.
router.get('/products/new-category', productService.fetchNewCategoryData);

module.exports = router;

Enter fullscreen mode Exit fullscreen mode

Passo 2: Criando o Cliente SOAP

Agora, no arquivo productService.js, é onde a mágica acontece. O primeiro passo é usar a node-soap para se conectar ao Web Service do cliente.

const soap = require('soap');
const config = require('../config'); // Arquivo com nossas configurações

// A URL do Web Service do cliente, geralmente terminando em .asmx?WSDL
const wsdlUrl = config.clientWebService.productsUrl;

async function fetchNewCategoryData(req, res, next) {
  try {
    // 1. Cria um cliente SOAP a partir da URL do WSDL
    const client = await soap.createClientAsync(wsdlUrl);

    // Se chegou aqui, a conexão foi bem-sucedida e o WSDL foi analisado.
    // O próximo passo é chamar o método que precisamos.

  } catch (err) {
    // É crucial tratar erros aqui! O serviço do cliente pode estar fora do ar.
    console.error('Falha ao conectar com o Web Service SOAP:', err);
    res.status(500).json({ message: 'Serviço externo indisponível.' });
  }
}

Enter fullscreen mode Exit fullscreen mode

Passo 3: Chamando o Método Específico e Tratando a Resposta

Com o client criado, podemos ver todos os métodos disponíveis e chamar o que foi criado para nós. Vamos chamá-lo de GetNewProductData em nosso exemplo.

As respostas de serviços SOAP .NET costumam vir em uma estrutura XML bem aninhada. A biblioteca node-soap converte isso para um objeto JSON, mas a estrutura aninhada permanece. É nosso trabalho navegar por esse objeto para encontrar os dados de que precisamos.

// ... continuação da função fetchNewCategoryData

try {
    // 2. Chama o método remoto específico (Ex: 'GetNewProductData')
    // O primeiro argumento é um objeto com os parâmetros que o método espera.
    // Neste caso, ele não esperava nenhum.
    const result = await client.GetNewProductDataAsync({});

    // 3. Navega na estrutura complexa da resposta para encontrar a lista de dados.
    // Este caminho pode variar, mas é comum em serviços .NET.
    const rawDataArray = result[0].GetNewProductDataResult.diffgram.NewDataSet.Table;

    // 4. Formata os dados para o padrão da nossa API
    const formattedData = rawDataArray.map(formatProductData);

    res.status(200).json(formattedData);

} catch (err) {
    console.error('Falha ao chamar o método ou processar a resposta:', err);
    res.status(500).json({ message: 'Erro ao obter dados do serviço externo.' });
}

// Função auxiliar para deixar os dados mais limpos
function formatProductData(productFromSoap) {
  return {
    id: productFromSoap.ID_PRODUTO,
    name: productFromSoap.NOME_PRODUTO,
    category: productFromSoap.CATEGORIA,
    // ... e assim por diante, transformando os nomes e valores conforme necessário
  };
}

Enter fullscreen mode Exit fullscreen mode

Desafios e Aprendizados

**- Estruturas de Dados: **O maior desafio foi entender a estrutura exata da resposta SOAP. O console.log(result) e ferramentas como o Postman ou SoapUI são seus melhores amigos para inspecionar e entender como navegar no objeto de resposta.

- Comunicação é Chave: A troca de e-mails com a equipe técnica do cliente foi fundamental. Sem uma comunicação clara sobre qual era o nome do novo método e qual a estrutura de dados esperada, o trabalho seria impossível.

**- Error Handling Robusto: **Em integrações, tudo pode dar errado: a rede pode falhar, o serviço do cliente pode estar fora do ar, ou a estrutura dos dados pode mudar inesperadamente. Envolver a lógica em blocos try...catch e prever cenários de falha é essencial para a estabilidade da sua aplicação.

Top comments (0)