O blog da AWS

Modernize seu servidor SOAP legado usando o Amazon API Gateway e o AWS Lambda – Parte 2

Por Daniel Abib, Enterprise Solution Architect, FSI – LATAM

Esta é a parte 2 da série de blog posts, aonde você aprenderá a construir uma solução de proxy para modernizar um servidor legado executando o protocolo SOAP. Esta é a segunda parte (num total de três) da série. Você pode ver na parte 1 os conceitos principais do protocolo SOAP e a abordagem de como fazer a conversão para protocolos mais modernos usando o Amazon API Gateway e o AWS Lambda.

Como apresentado na parte 1 do blog, iremos agora partir para uma sugestão de implementação da arquitetura abaixo, criando uma possível solução para continuar utilizando um servidor SOAP legado, expondo seus serviços através do protocolo REST:

Vamos construir a solução usando o AWS SAM

O Serverless Application Model (SAM) é uma solução de código aberto para criar aplicativos sem servidor (Serverless). Ele fornece uma sintaxe simplificada para criar funções, APIs, bancos de dados e eventos. Com apenas algumas linhas, você pode definir o aplicativo desejado e modelá-lo usando uma estrutura no formato de YAML. Durante a implantação, o AWS SAM transforma e expande a sintaxe do SAM para se adequar as necessidades do AWS CloudFormation, permitindo que você crie aplicativos sem servidor mais rapidamente.

O AWS SAM também fornece uma ferramenta de linha de comando, a AWS SAM CLI, que facilita a criação e o gerenciamento de aplicativos sem servidor (Serverless). Com a AWS SAM CLI, podemos criar automaticamente um bucket no S3, uma API, uma função Lambda com base em suas credenciais locais da AWS.

Como o AWS SAM se integra a outros serviços da AWS, a criação de aplicativos sem servidor (Serverless) oferece os seguintes benefícios:

  • Configuração de implantação única (Single-deployment configuration). O AWS SAM facilita a organização de componentes e recursos relacionados e opera em uma única stack (solução de componentes). Você pode usar o AWS SAM para compartilhar a configuração entre recursos, como memória e tempos limite de execução, e implantar todos os recursos relacionados juntos como uma única entidade com versão.
  • É uma extensão do AWS CloudFormation. Como o AWS SAM é uma extensão do AWS CloudFormation, você pode usar o conjunto completo de recursos, funções intrínsecas e outros recursos disponíveis no AWS CloudFormation.
  • Melhores práticas recomendadas. Você pode usar o AWS SAM para definir e implantar sua infraestrutura como código (IaC). Isso possibilita que você use e aplique as melhores práticas, como revisões de código, versionamento, entre outros benefícios. Além disso, com algumas linhas de configuração, você pode habilitar implantações (deployments) seguros por meio do CodeDeploy e habilitar o rastreamento usando o AWS X-Ray.
  • Depuração e testes locais. A CLI do AWS SAM permite criar, testar e depurar localmente aplicativos sem servidor definidos por modelos do AWS SAM. A CLI fornece um ambiente de execução semelhante ao Lambda localmente. Ele ajuda você a detectar problemas antecipadamente, fornecendo paridade com o ambiente de execução real do AWS
  • Integração com ferramentas de desenvolvimento. Você pode usar o AWS SAM com um conjunto de ferramentas da AWS ou com sua IDE de preferência para criar aplicativos sem servidor.

Para esta implementação, existem os seguintes pré-requisitos:

  • NodeJS 14.x ou superior (usaremos o NodeJS 16.x neste exemplo)
  • NPM (gerenciador de pacotes do NodeJS) versão 6x ou posterior
  • AWS SAM versão 1.53.0 ou posterior
  • Docker (é opcional, obrigatório apenas se você quiser testar sua API localmente)
  • curl – curl é uma ferramenta de linha de comando de código aberto para transferir dados e fazer requisições web usando vários protocolos de rede. Vamos usá-lo para testar nossa API localmente, bem como na AWS. Se você não estiver familiarizado com o curl, poderá usar o Postman, Insomnia, HTTPie, SoapUI ou outro software similar.

Neste blog, vamos usar o AWS Cloud 9 como um IDE (Ambiente de Desenvolvimento Integrado) para o desenvolvimento e testes do código de exemplo, mas você pode usar aquele que está acostumado a codificar. Se você não sabe como criar este ambiente de desenvolvimento virtual, há uma explicação nesse link.

Aqui está a sequência de passos que temos que fazer:

  1. Abra o serviço Cloud9 no console de gerenciamento da AWS (AWS console)
  2. No terminal ou usando os menus, crie uma pasta para o projeto chamada proxySoapServer com uma subpasta chamada ./src. A pasta ./src conterá o código Lambda necessário para esta solução.
mkdir proxySoapServer && cd proxySoapServer
  1. Crie os seguintes arquivos em branco:
    • ./template.yaml
    • ./src/app.js
    • ./src/package.json

Opção A: Você pode usar o editor Cloud9 – Menu File -> New File

Abra B: Você pode clicar com o botão direito do mouse na pasta à esquerda e selecionar Novo arquivo:

Opção C: você pode usar um comando bash no terminal no Cloud9:

touch template.yaml ./src/app.js ./src/package.json

A estrutura do projeto (pasta e arquivos) deve estar assim:

  1. Abra o arquivo template.yaml e copie o seguinte conteúdo no arquivo:
# © 2022 Amazon Web Services, Inc. or its affiliates. All Rights Reserved.

# This AWS Content is provided subject to the terms of the AWS Customer Agreement
# available at http://aws.amazon.com/agreement or other written agreement between
# Customer and either Amazon Web Services

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: proxySoapServer

Resources:
  NumberToWordsFunction:
    Type: AWS::Serverless::Function 
    Properties:
      CodeUri: src/
      Handler: app.handler
      Runtime: nodejs14.x
      Events:
        NumberToWordsApi:
          Type: Api 
          Properties:
            Path: /
            Method: post

Outputs:
  NumberToWords:
    Description: "Test the API Gateway endpoint URL for Prod stage for NumberToWords"
    Value: !Sub "curl -i -X POST https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/ -d '{\"data\": 123}'"

  WatchLogsLocally:
    Description: "To watch the logs locally, use the following command"
    Value: !Sub "sam logs -n NumberToWordsFunction --stack-name soapProxy --tail"

Você notará que a sintaxe do arquivo template.yml se parece exatamente com o AWS CloudFormation. O motivo é que os templates do AWS SAM são uma extensão dos modelos do AWS CloudFormation. Isso significa que qualquer recurso que você possa definir no AWS CloudFormation também pode ser definido em um modelo do AWS SAM, mas usar o AWS SAM será mais ágil para desenvolver, testar e implantar soluções sem servidor na AWS.

Neste template do AWS SAM, estamos definindo uma função Lambda chamada NumberToWords (verifique a linha 12) e um REST API Gateway expondo o método /post (linhas 19 a 22). O código fonte da função Lambda estará na pasta /src (linha 15), em um arquivo chamado app.js (linha 16) com uma função chamada “handler”. Nas linhas 25 a 32 definimos as saídas (outputs) de nossa solução.

Lembre-se de salvar o arquivo.

  1. A próxima etapa deste blog é copiar o código-fonte da nossa função Lambda. Abra o arquivo app.js na pasta ./src e copie o seguinte código:
// © 2022 Amazon Web Services, Inc. or its affiliates. All Rights Reserved.

// This AWS Content is provided subject to the terms of the AWS Customer Agreement
// available at http://aws.amazon.com/agreement or other written agreement between
// Customer and either Amazon Web Services

var parseString = require('xml2js').parseString;
const soapRequest = require('easy-soap-request');

/* 
Main Lambda Handler Function 
*/
exports.handler = async (event, context) => {
    let response;
    
    if (!event || !event.body) {
        return {'statusCode': 400, 
                'body': JSON.stringify({message: "Missing parameter {\"data\": number}"})
        };
    }
    
    const valueToConvert = JSON.parse(event.body).data;
    console.log ("Value to Convert: " + valueToConvert);

    try {
        let valueInSring = await callSoapServer(valueToConvert);
        
        response = {'statusCode': 200, 'body': JSON.stringify({message: valueInSring})};
                    
    } catch (err) {
        return err;
    }
    
    return response;
};


/* 
Function to make a API call to a SOAP server 
*/
async function callSoapServer (valueToConvert) {
    let ret;
    const url = 'https://www.dataaccess.com/webservicesserver/NumberConversion.wso?op=NumberToWords';
    
    const sampleHeaders = {
      'Content-Type': 'text/xml;charset=UTF-8'
      };
      
    const xml = '<?xml version="1.0" encoding="utf-8"?> \
                 <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> \
                    <soap:Body> \
                      <NumberToWords xmlns="http://www.dataaccess.com/webservicesserver/"> \
                        <ubiNum>' + valueToConvert + '</ubiNum> \
                      </NumberToWords> \
                    </soap:Body> \
                 </soap:Envelope>';
                 
      const { response } = await soapRequest({ url: url, headers: sampleHeaders, xml: xml});
      const { body } = response;
      
    console.log ("Response from SOAP Server: " + JSON.stringify(response));
    
    // Parsing XML to get the value
    parseString(body, function (err, result) {
        if (!err) {
            ret = result['soap:Envelope']['soap:Body'][0]['m:NumberToWordsResponse'][0]['m:NumberToWordsResult'][0];
        }
    });

    return ret;
}

Lembre-se de salvar o arquivo também.

Esta função do Lambda é um aplicativo proxy simples para converter os dados de entrada do formato JSON para o formato XML (linhas 49 a 56), o “Application-type” de Application/json” para “text/xml (linhas 45 a 47) e chamar um servidor SOAP público que converte número em palavras (linha 58).

O que este codigo faz é, se você enviar um número inteiro como “1029” no formato JSON, haverá uma transformação para XML, chamando o servidor legado que utiliza SOAP e ele retornará uma string com valor “mil vinte e nove” em XML, que será convertido em JSON e retornará para sua aplicação cliente.

O servidor vai retornar a palavra correspondente ao número passado como parâmetro, limitado a quatrilhões. Você pode verificar o site deles no seguinte URL:

https://www.dataaccess.com/webservicesserver/NumberConversion.wso?op=NumberToWords

Este servidor espera o seguinte Envelope  SOAP (SOAP 1.1 à esquerda e SOAP 1.2 à direita):

E as respostas que o servidor fornecerá estão no seguinte formato (SOAP 1.1 à esquerda e SOAP 1.2 à direita):

  1. Devido ao fato de usar bibliotecas externas no código Lambda, devemos atualizar o arquivo package.json e executar o comando “npm install” posteriormente. Abra na pasta ./src o arquivo package.json e copie o seguinte conteúdo:
{
  "name": "RestToAPIProxyExample",
  "version": "1.0.0",
  "description": "Example of proxy a legacy SOAP server using AWS Lambda and Amazon API Gateway using REST",
  "main": "app.js",cd
  "author": "Daniel Abib",
  "license": "MIT",
  "dependencies": {
    "easy-soap-request": "^4.2.0",
    "xml2js": "^0.4.23"
  }
}
  1. No terminal do Cloud9, altere o diretório para ./src e execute o seguinte comando para instalar as bibliotecas externas:
cd src && npm install

Você notará que existem 2 dependências e a pasta node_modules foi criada no ./src para incluir essas bibliotecas.

  1. Antes de testar o aplicativo, precisamos construir os artefatos usando o comando “sam build” no diretório raiz do projeto.
cd .. && sam build


 O comando “sam build” processa o arquivo de template do AWS SAM, o código fonte do aplicativo e quaisquer arquivos e dependências específicos da linguagem escolhida. O comando cria e copia artefatos no formato e local esperados (diretório .aws-sam) para as etapas subsequentes em seu fluxo de trabalho. Você pode especificar dependências em um arquivo de manifesto que inclui em seu aplicativo, como requirements.txt para funções do Python ou package.json para funções do NodeJS. A saída do comando “sam build” deve ser semelhante à imagem a seguir: 
        
       
    1. Agora é hora de executar nosso aplicativo localmente para testá-lo. O AWS SAM permite que você execute seu aplicativo sem servidor (Serverless) localmente para desenvolvimento e teste rápidos. Quando você executa o comando a seguir em um diretório que contém suas funções e seu template do AWS SAM, ele cria um servidor HTTP local (usando Docker) que hospeda todas as suas funções.
  Você pode usar o comando “sam local start-api” para emular a execução de um Amazon API Gateway e receber a solicitação localmente, mas é obrigatório ter o docker rodando em seu ambiente local.
sam local start-api


**IMPORTANTE** Se você não tiver o docker em execução localmente em sua máquina, ignore esta etapa e implante o aplicativo conforme definido na Parte III deste blog. No Cloud9, o docker está em execução por padrão.

Você pode abrir outro terminal (clique no botão + à direita de “guia Immediate” e escolha Novo Terminal) para mostrar a execução da chamada da API REST (método de solicitação POST usando curl) e manter o primeiro terminal aberto para mostrar como a o docker cria contêiner para executar o Amazon API Gateway e a função Lambda.

Você pode testar sua API local usando o seguinte comando curl (post):

curl -i -X POST localhost:3000/ -H "Content-Type: application/json" -d '{"data": "188"}'
 A saída deve se parecer com a imagem a seguir: 
        Nesta execução local, o comando curl (aplicativo cliente) enviou uma solicitação REST /POST ao Amazon API Gateway em execução local de um contêiner docker. Essa solicitação tinha Content-Type como Application/json. O API Gateway enviou um playload em JSON para a função Lambda que “empacotava / envelopa” essas informações em um formato XML. Após essa transformação, a função Lambda enviou a solicitação ao servidor SOAP legado e recebeu um XML com o número transformado em palavras. Para poder responder a essa solicitação em REST, a função Lambda decompôs o XML e coletou os dados necessários para criar o JSON e o enviou para o aplicativo cliente (curl). Algumas informações importantes na execução (números da figura acima): 
       
    • Uma imagem do AWS Lambda e do Amazon API Gateway foi carregada no docker para poder executá-lo localmente
 
    • O AWS Lambda conseguiu recuperar o valor correto do payload
 
    • AWS Lambda fez uma solicitação ao servidor SOAP legado que retornou o número em palavras
 
    • O resultado da API REST foi bem-sucedido (código de status HTTP 200)
 
    • Embora o servidor SOAP tenha respondido com um tipo de aplicativo Text/XML no cabeçalho HTTP, o cliente (curl) recebeu um tipo de aplicativo como application/json devido à conversão executada por nossa solução
 
    • O resultado final no formato JSON foi o número convertido em palavras.
   

Implantando a solução na AWS

Agora é hora de implantar (deploy) esta solução SOAP Proxy na AWS. Você verá como é fácil implantar uma solução usando o AWS SAM. Execute os seguintes passos:
    • Pressione Control+C no terminal que está executando o comando “sam local start-api”, use um segundo terminal ou abra um novo para executar o comando “sam deploy -g”
   
sam deploy -g
  • Preencha os seguintes valores quando solicitado:

Este comando (sam deploy -g) implanta seu aplicativo na nuvem da AWS. Ele pega os artefatos que foram criados, os empacota e os carrega em um bucket do Amazon Simple Storage Service (Amazon S3) que o AWS CloudFormation usará para criar o aplicativo.

É isso... não há mais nada a fazer e sua solução está funcionando na AWS. Simples, não é?

Este único comando criou um API Gateway (com stage e deployment), uma função Lambda, uma “role” de execução, um bucket S3 para armazenar os artefatos, tudo isso chamado o AWS CloudFormation que implanta a solução e toda a configuração necessária para executar este serviço na AWS em seu nome.

Como resultado, as saídas do AWS CloudFormation informam ao URL que sua API REST está escutando.

Você pode usar o seguinte comando para testar sua solução:

curl -i -X POST https://mqwp8meppe.execute-api.us-east-1.amazonaws.com/prod/ -d ‘{“data”: 123}’

(OBS1: você deve substituir a URL pela que você gerou na sua implantação)

(OBS2: você pode copiar o comando acima na sessão de saída do “sam deploy”)

Limpar o workload que foi gerado

Usando o serviço AWS Serverless, os clientes pagam apenas pelo que usam. Se não houver solicitação para AWS Lambda ou Amazon API Gateway, você não será cobrado.

Ambos os serviços usados ​​aqui têm um nível gratuito conforme definido abaixo:

Serviço Nível gratuito
Amazon API Gateway O nível gratuito do Amazon API Gateway inclui um milhão de chamadas de API recebidas para APIs REST, um milhão de chamadas de API recebidas para APIs HTTP e um milhão de mensagens e 750.000 minutos de conexão para APIs WebSocket por mês por até 12 meses.
AWS Lambda O nível gratuito do AWS Lambda inclui um milhão de solicitações gratuitas por mês e 400.000 GB-segundos de tempo de computação por mês, utilizáveis ​​para funções com processadores x86 e Graviton2, em conjunto.

Mas, se você quiser limpar sua conta da AWS, basta executar um comando do AWS SAM:

 sam delete

Você precisa confirmar a exclusão do aplicativo, bem como os artefatos armazenados no S3. Este será o resultado:

Se você tiver outros casos de uso para modernizar arquiteturas legadas SOAP e quiser compartilhá-lo comigo, entre em contato comigo no LinkedIn e tentarei ajudar. https://www.linkedin.com/in/danielabib/


Sobre o autor

Daniel Abib é Enterprise Solution Architect na AWS, com mais de 25 anos trabalhando com gerenciamento de projetos, arquiteturas de soluções escaláveis, desenvolvimento de sistemas e CI/CD, microsserviços, Serverless e segurança. Ele trabalha apoiando clientes corporativos, ajudando-os em sua jornada para a nuvem.