npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@seniorsistemas/fsw-aws-lambda

v0.0.9

Published

Biblioteca de utilitários para construção de lambdas no ambiente SKD G7 para interceptação de primitivas.

Downloads

9

Readme

Fábrica de Software Senior - Aws Lambda Lib

Biblioteca da Fábrica de Software Senior para padronização e auxílio na construção de constomizações utilizando lambdas no ambiente SDK G7 para interceptação de primitivas.


Instalação

A partir do root de um projeto NodeJs, instalar a dependência:

npm install --save @seniorsistemas/fsw-aws-lambda

Feito isso, os módulos já estarão disponíveis para utilização:

require('@seniorsistemas/fsw-aws-lambda');

Dependências opcionais

São dependências requeridas por alguns módulos da lib (o módulo core não requer dependências).

npm install --save axios moment

Principais módulos

A biblioteca é distribuída como módulos no formato CommonJS por compatibilidade nativa com Node v10.16.3 (versão atual suportada pela IDE AWS Cloud9). Os principais módulos são:

  • @seniorsistemas/fsw-aws-lambda: Módulo principal, provê funções para manipular o evento nativo da Lambda AWS, configuração da resposta da lambda e gerencia a execução de regras;
  • @seniorsistemas/fsw-aws-lambda/utils: Utilitários;
  • @seniorsistemas/fsw-aws-lambda/services: Services com lógicas em comum entre projetos.

Utilização

A utilização da biblioteca visa padronizar o tratamento de eventos recebidos e resposta retornada pela função Lambda e a execução de regras de execução. A documentação também pode ser consultada na respectiva documentação de código em cada função e classe.

Com a integração da biblioteca, o index.js da função lambda deve-se assimilar com o modelo abaixo:

index.js

// Importação de funções e classe para execução de validações.
const {
    lambdaEvent,
    lambdaResponse,
    AsyncRuleValidator
} = require('@seniorsistemas/fsw-aws-lambda');

// Função principal da lambda, sempre deve ser 'async' ou retornar 
// uma Promise com o payload de resposta.
exports.handler = async event => {

    // Retorna o payload da requisição original do evento.
    // Sempre será um objeto JSON.
    const body = lambdaEvent.parseBody(event);

    // Lê e extrai informações do evento original da função lambda e
    // define as configurações de ambiente, como o ambiente de execução
    // (development, homologx, production) e variáveis de ambiente, como
    // a URL da plataforma e o token para autenticação.
    const eventInfo = lambdaEvent.createEventInfo(event);

    // Criação do executor das regras de validação, recebe como parâmetro
    // as informações extraídas do evento.
    return new AsyncRuleValidator(body, eventInfo)
        .validate([ // Adiciona as regras de validação a serem executadas.
            'rf01',
            'rf02',
            /* outras regras */
        ])

        // Após todas as regras serem executadas, avalia se há erros de
        // validação e retorna a resposta correspondente, sendo elas:
        // Erro de cliente (código 400) caso houveram erros de validação,
        // sucesso (código 200) caso contrário.
        .then(validationResult => {
            if (validationResult.hasErrors()) {
                return lambdaResponse
                .validationError(validationResult.getErrorsAsString());
            }

            return lambdaResponse.success(body);
        })

        // Em caso de alguma exceção ou erro inesperado, retorna erro
        // interno (código 417).
        .catch(lambdaResponse.internalError);
};

Customizando o ambiente de execução do evento

Ao executar o código:

const eventInfo = lambdaEvent.createEventInfo(event);

Já temos em mãos as variáveis de ambiente necessária para a execução das regras de validação. Entretanto, pode ser necessária a adição de mais variáveis ou a definição de valores padrão para as mesmas.

Os valores padrão podem ser informados como segundo parâmetro da função createEventInfo, tendo como definição:

interface EnvironmentData {
    basePlatformUrl: string;
    bearerToken: string;
}

Por exemplo:

const eventInfo = lambdaEvent.createEventInfo(event, {
    basePlatformUrl: 'https://platform.senior.com.br/t/senior.com.br/bridge/1.0/rest',
    bearerToken: 'Bearer 15c2a9eca2e0f8faac36de609c7d05ca'
});

Caso não forem informados os valores padrão de variáveis de ambiente, serão utilizados os declarados nas constantes environments.js conforme o ambiente identificado a partir dos dados do evento, no atributo event.environment.

ARQPDT-1923: O usuário liberado pelo SDK (ainda) não possui acesso às configurações de variáveis de ambiente, conforme documentação oficial da AWS. Portanto, faz-se necessário outro meio para definir as variáveis de ambiente.

Criando evento de execução com autenticação da lambda (Autenticação de aplicação externa)

Em alguns momentos é necessário realizar chamadas HTTP para a plataforma com um token que tenha permissões de administrador e não utilizar o token do usuário recebido no evento original. Através desse recurso é possível criar o evento de execução para extrair as informações do evento original e autenticar a lambda na plataforma através da chaves de aplicações geradas na plataforma.

Ao optar por utilizar essa forma de criação do evento, é necessário substituir a implementação utilizada no item "Customizando o ambiente de execução do evento" dessa documentação.

O metodo recebe como parâmetro o evento original, a chave de acesso e a senha de acesso (Essa informações serão geradas através da plataforma).

const eventInfo = await lambdaEvent.createEventInfoWithAuthentication(event, 'PwBbpdyzKSEGrZmfeEiCkrb3awEa', 'mXVJMIs2o7pTsVjMUpaWyVVKlFUa');

Ao executar esse trecho de código será criada uma nova variável no eventInfo chamada "lambdaToken". Através dessa variável é possível obter um token válido para chamadas para a plataforma. Essa informação pode ser acessada da seguinte forma:

const eventInfo = await lambdaEvent.createEventInfoWithAuthentication(event, 'PwBbpdyzKSEGrZmfeEiCkrb3awEa', 'mXVJMIs2o7pTsVjMUpaWyVVKlFUa');
let lambdaToken = eventInfo.lambdaToken;

AsyncRuleValidator

Como o próprio nome sugere, é um validador de regras assíncrono (tudo é ou vira uma Promise).

As regras de validação são apenas funções, não precisam, necessariamente, serem módulos externos, apenas precisam obedecer à seguinte interface:

function (body, event) {
    return 'Mensagem de erro';
}
// Ou
function (body, event) {
    return ['Uma mensagem de erro', 'Outra mensagem de erro'];
}
// Ou
async function (body, event) {
    return 'Mensagem de erro';
}

Onde o parâmetro body é o payload da requisição convertido no formato objeto JSON e event é o objeto contendo os dados de evento original da função lambda. Cada regra de validação pode ser síncrona ou assíncrona, entretanto, a execução sempre será assíncrona e podem retornar um, nenhum, ou uma lista de erros de validação.

Possui dois métodos principais para validação:

Ambos os métodos aceitam dois formatos de parâmetros:

  1. O nome da regra. Nesse caso, a regra será carregada de um arquivo no diretório fixo src/rules a partir do root do projeto. Por exeplo: 'rf01' será requerido do arquivo '/src/rules/rf01.js'. O arquivo da regra deve obedecer arquitetura de módulos, exportando a função para validação: module.exports = async (body, event) => {}.

  2. A função para execução das regras, podendo conter nenhum, um ou dois parâmetros e retornar uma mensagem, uma lista de mensagens ou uma Promise.

AsyncRuleValidator.validate()

Executa uma série de regras de validação de forma assíncrona, onde todas as regras serão executadas ao mesmo tempo e o resultado será apresentado apenas quando todas as regras terminarem sua execução.

Exemplo:

asyncRuleValidator
    .validate([
        'rf01',
        function (body) {  return 'Mensagem de erro'  },
        async (body, event) => ['Mensagem de erro'] ,
        () => 'Mensagem de erro'
    ]).then(/* ... */);

AsyncRuleValidator.validateOneByOne()

Executa uma série de regras de validação, executando uma regra por vez. Cada regra de validação pode ser síncrona ou assíncrona, entretanto, a execução sempre terá comportamento síncrono (a execução de uma regra trava a execução das seguintes). A primeira regra que retornar uma mensagem de validação excerrará a execução da cadeia de regras.

Exemplo:

asyncRuleValidator
    .validateOneByOne([
        'rf01',
        function (body) {  return 'Mensagem de erro'  },
        async (body, event) => ['Mensagem de erro'] ,
        () => 'Mensagem de erro'
    ]).then(/* ... */);

Tratando o retorno das regras de validação

Após a execução bem sucedida das regras de validação, será invocado o método .then() da Promise retornada pelos métodos de validação. Este método receberá como argumento uma instância da classe ValidationResult a qual tem a responsabilidade de armazenar todas as mensagens retornadas por regras de validação e possui métodos auxiliares para posterior tratamento das mensagens.

Principais métodos da classe ValidationResult:

  • .hasErros(): avalia se houveram erros de validação;
  • .getErrors(): retorna um objeto contendo todas as mensagens de erro de validação, se houver.
  • .getErrorsAsString() retorna uma string concatenando todas as mensagens de erro de validação separadas pelo caractere quebra de linha \n.

Caso alguma regra falhar na execução e lençar uma exceção, será invocado o método .catch() da Promise contendo informações sobre qual regra falhou e o detalhe da exceção.

Padrão de retorno da função lambda

Os retornos da função lambda customizada são criados pelas funções do módulo lambda-response, tanto para sucesso, falha em regras de validação e erros inesperados.

O padrão de retorno sempre será:

{
    statusCode: 200 | 400 | 417
    headers: {
        'Content-Type': 'application/json' | 'text/plain',
        'X-Senior-FSW': 'Customizacao'
    },
    body: {} | ''
}

Importante: Em todos os cenários, o header X-Senior-FSW é retornado na resposta com o valor Customizacao, identificando que esse retorno foi interceptado e, possivelmente, modificado pela equipe de Customização da Fábrica de Software Senior.

Os códigos padrão de status HTTP retornados são:

  • 200: Sucesso;
  • 400: Erro de validação retornado por regras;
  • 417: Erro interno, durante a execução de regras ou outro erro inesperado.

O Content-Type pode variar dependendo do parâmetro informado para o body, caso o body seja um objeto JSON, o Content-Type será application/json, caso o body seja um texto, o Content-Type será text/plain. Quando uma resposta for gerada por exceções ou erros inesperados, o corpo da resposta sempre terá o prefixo [FSW-ERROR].

Funções para construção da resposta

As funções disponíveis para criação do payload de resposta da função lambda são os seguintes:

const { lambdaResponse } = require('@seniorsistemas/fsw-aws-lambda');

const body = {}; // Também pode ser string.

lambdaResponse.success(body);

lambdaResponse.validationError(body);

lambdaResponse.internalError(body);

const httpStatus = 404;
lambdaResponse.response(httpStatus, body);

Validando existência de propriedades em objetos

Por muitas vezes é necessário validar se determinada propriedade/atritbuo de um objeto existe e se o valor dele é diferente de vazio.

Existem duas formas de realizar esse tratamento:


const { lambdaUtils } = require('@seniorsistemas/fsw-aws-lambda');

//Objeto de exemplo
const obj = {
        name: 'Fulano de tal',
        nickname: '',
        city: 'Blumenau',
        infos: {
            cel: '47999999999'
        },
        emptyObj: {
            name: ''
        }
};

//forma nativa - Valida se a propriedade existe e tem valor. nesse caso a propriedade nickname existe mais não tem valor, então a comapração retoraná false

if(!!obj.nickname) {
    //implementation
}

// Via utiliário - Realiza a mesma validação. Se a propriedade existe e tem valor
if(lambdaUtils.isPresent(obj.nickname)){
    // implementation
}

Requisições para a plataforma

A biblioteca possui um utilitário para facilitar a realização de requisições para a plataforma SeniorX, funciona como um wrapper para as funções do axios. Tem por objetivo:

  • Autenticação com a plataforma, adiciona o token no cabeçalho da requisição;
  • Tratamento da resposta com sucesso;
  • Tratamento da resposta com erro. Realiza logs e adiciona informações sobre a URL e o erro ocorrido (não suprime a exceção, a mesma será propagada).

OBS.: Requer dependência com [email protected] (ou posterior).

Exemplo:

const { axiosW } = require('@seniorsistemas/fsw-aws-lambda/utils');

const eventInfo = {}; // O mesmo evento recebido pelas regras de validação.

axiosW.platformGet(eventInfo, '/uri');
//    .platformHead(eventInfo, uri, config)
//    .platformDelete(eventInfo, uri, config)
//    .platformPut(eventInfo, uri, data, config)
//    .platformPost(eventInfo, uri, data, config)
//    .platformPatch(eventInfo, uri, data, config)
//    .get(url, config)
//    .head(url, config)
//    .delete(url, config)
//    .put(url, data, config)
//    .post(url, data, config)
//    .patch(url, data, config)

Requisições para a plataforma via utilitário (PlatformApi)

Esse novo utilitário PlatformApi facilita as chamadas a outras primtivas da Plataforma de uma maneira mais simples.

Lembrando que o método do tópico acima ainda continua funcional.

Esse novo método é apenas uma absstração que utiliza por baixo as chamadas utilizando o utiliátios axiosW.

    const {
        lambdaEvent,
        PlatformApi
    } = require('@seniorsistemas/fsw-aws-lambda');

   /*Evento vindo da requisição*/ 
    const eventInfo = lambdaEvent.createEventInfo(event);

    const userData = await PlatformApi.Get(eventInfo,'/usuarios/userManager/queries/obterMeusDados');

    /*O utilitário possui os seguintes métodos:
    
    PlatformApi.Get(event,primitive,params)
    PlatformApi.Delete (event,primitive,params) 
    PlatformApi.Head  (event,primitive,params)
    PlatformApi.Post (event, primitive, data, params)
    PlatformApi.Put (event, primitive, data, params)
    PlatformApi.Patch = (event, primitive, data, params) 
        
    */

Além das chamadas para a plataforma utilizando o token do evento original (usuário logado na plataforma), é possível realizar chamadas utilizando o token obtido na lambda através de uma autenticação de aplicação externa. Para mais informações, verificar o item "Criando evento de execução com autenticação da lambda (Autenticação de aplicação externa)" dessa documentação.

    const {
        lambdaEvent,
        PlatformApi
    } = require('@seniorsistemas/fsw-aws-lambda');

   /*Evento vindo da requisição*/ 
    const eventInfo = await lambdaEvent.createEventInfoWithAuthentication(event, 'PwBbpdyzKSEGrZmfeEiCkrb3awEa', 'mXVJMIs2o7pTsVjMUpaWyVVKlFUa');

    const userData = await PlatformApi.GetWithLambdaToken(eventInfo,'/usuarios/userManager/queries/obterMeusDados');
    
    /*O utilitário possui os seguintes métodos:
    PlatformApi.GetWithLambdaToken(event,primitive,params)
    PlatformApi.DeleteWithLambdaToken (event,primitive,params) 
    PlatformApi.HeadWithLambdaToken  (event,primitive,params)
    PlatformApi.PostWithLambdaToken (event, primitive, data, params)
    PlatformApi.PutWithLambdaToken (event, primitive, data, params)
    PlatformApi.PatchWithLambdaToken = (event, primitive, data, params) 
    */

Consumindo serviços da G5

A biblioteca possui um utilitário para auxiliar nas chamadas aos Webservices SOAP da G5. Esse utilitário realiza a chamada no SXIAPI que é uma biblioteca que possibilita a chamada dos WS SOAP G5, enviando um corpo em JSON e recebendo o corpo também em JSON. Visto que os webservices SOAP da G5 trabalham com dados no formato XML.

Para maiores informações sobre o SXIAPI verificar o link a seguir presente na página dev.senior.com.br: SXIAPI

OBS.: Chamadas a G5 devem ser evitadas a todo custo quando estamos em um contexto de execução dentro de customizações na G7, visto que é uma chamada externa que aumenta consideravelmente o tempo de execução da função lambda, aumentando assim o tempo de respota ao usuário. Esse recurso deve ser utilizado apenas se não existir outra solução.

Exemplo:

const {
    lambdaEvent,
    G5Api
} = require('@seniorsistemas/fsw-aws-lambda');


 /*Evento vindo da requisição*/ 
    const eventInfo = lambdaEvent.createEventInfo(event);

    /*Instância classe de utiliários da chamada as APIS da G5
    Parâmetros:
        - sxiServer: Endereço onde se encontra deployado o utilitário SXI para comunicação com a G5
        - sxiContext:  Contexto que o utilitário SXI responde dentro do servidor Glassfish da G5
        - g5Server: Endereço onde os Webservices SOAP da G5 estão implantados
        - user: Nome do Usuário G5 para execução dos webservices
        - token: Token da plataforma referente ao usuário logado, ou Senha do usuário da G5 informado
    */     
    const g5 = new g5Api('http://desktop-lb7k1kk:8000','API','http://desktop-lb7k1kk:8000','senior', eventInfo.platformToken);

    /* Realizada a chamada do WS da G5 através do método callService passando como parâmetro:
       - g5Module: Módulo da G5 referente ao serviço a ser executado
       - service: Nome completo do webservice da G5
       - port: Nome da Porta do webservice da G5
       - body: Objeto contendo o corpo da requisição (parâmetros de entrada no foramto json)
       - dataSourceName: Parâmetro opcional, quando passado altera o nome do objeto principal retornado
    */ 

   const bodyCol = {
        numEmp: 1,
        abrTipCol: "1",
        iniPer: "01/01/2000",
        fimPer: "31/01/2001"
   };

    const response = await g5.callService("rubi","com.senior.g5.rh.fp.colaboradoresAdmitidos","ColaboradoresAdmitidos",bodyCol);

Utilitário para envio de E-mail

Esse utilitário é um facilitador para realizar envio de e-mail através da primitiva de notifação da Pltaforma Senior X: /platform/notifications/actions/notifyUser

O utiliário E-mail Service possui dos métodos para realizar o envio:

sendEmail Realiza o envio de um email simples, conteúdo em texto Plano, pramâmetros:

  • Evento: Enviar o eventIndo que contém os metadados da requisição
  • Destinatário: Lista de destinatários, pode ser passado mais de um e-mail separando com " , - virgula"
  • Assunto: Assunto do E-mail
  • Contéudo: Corpo do E-mail em texto Plano

sendEmailHTML Realiza o envio de um email com conteúdo formatado em HTML, pramâmetros:

  • Evento: Enviar o eventIndo que contém os metadados da requisição
  • Destinatário: Lista de destinatários, pode ser passado mais de um e-mail separando com " , - virgula"
  • Assunto: Assunto do E-mail
  • Contéudo: Corpo do E-mail em HTML

Ambos metódos retornam um objeto de responto se sucesso o retorno será: { ok: true }


const { lambdaEvent } = require('@seniorsistemas/fsw-aws-lambda');
const { emailService } = require('@seniorsistemas/fsw-aws-lambda/services/email-service');


/*Evento vindo da requisição*/ 
const eventInfo = lambdaEvent.createEventInfo(event);

const responseEmail = await emailService.sendEmail(eventInfo,'[email protected]','Teste Via Customização','Conteúdo');

console.log(responseEmail);

const responseEmailHTML = await emailService.sendEmailHTML(eventInfo,'[email protected],[email protected]','Teste Via Customização HTML','<h1>Conteúdo</h1>');

console.log(responseEmailHTML);

Testando as regras dentro do Cloud9

Após criada, a função lambda pode ser executada e depurada diretamente da IDE AWS Cloud9. Para isso, é necessário abrir o menu de execução da lambda:

  1. No menu lateral direito, clicar na aba "AWS Resources" para listar as lambdas criadas. Escolha a lambda desejada para execução e clique com o botão direito, selecione a opção "Run" e, então, "Run Local". Menu de execução AWS Resources, indicando onde acessar o submenu "Run Local"

  2. A aba que será aberta, é a aba de configuração de execução da função lambda. Para executar a função basta clicar no botão "Run" e para executar em modo debug, basta ativar o botão "Run in debug mode" e, então, clicar no botão "Run". Note que no payload há um atributo "environment": "development", este atributo é customizado e não existirá em eventos reais quando a lambda for invocada, ele é utilizado para indicar à biblioteca configurar o ambiente de execução com as variáveis de desenvolvimento. Todo o conteúdo do campo payload será o valor da variável event na execução da lambda. Executar função lambda com payload customizado

  3. Durante a execução em modo de depuração, no topo da janela de execução é possível controlar os passos de avanço da depuração, acompanhar valor de variáveis e a stack de execução. Clicando na aba "Immediate" na parte inferior da janela, será aberto um console para depuração onde é possível executar um código dentro do contexto do breakpoint. Controle de breakpoint e console de depuração

Contribuindo com o projeto

Para ver como pode contribuir com o projeto, leia as instruções de contribuição.

Licença

Senior Sistemas SA © Ver licença em LICENSE.

Autores: Luiz Nazari <[email protected]> Diego Cassandri <[email protected]> Felipe Gonçalves <[email protected]>