Assista no Youtube a Conferência Sails 2023
logo Bem-vindo ao Sails.js Tech Brasil!

O Sails.js, como ferramenta de desenvolvimento de sistemas digitais e de código aberto, facilita a criação de aplicativos Node.js personalizados e de nível empresarial . Sails.js cria aplicativos Node.js práticos e prontos para produção em questão de semanas, não meses. Sails é a mais popular tecnologia do tipo Modelo x Visão x Controle (MVC) para Node.js sendo projetada para emular o padrão MVC como Ruby on Rails, mas com suporte para os requisitos de aplicativos modernos, por APIs orientadas a dados e com uma arquitetura escalável, orientada a serviços.

O truque da tecnologia se baseia num gerador de códigos já existente (Express.js) expandido e fornecido pelo time principal do Sails para facilitar a criação de diversos recursos prontos, tais como autenticação, registro, verificação de e-mail e faturamento. Além disso, incorpora ferramentas que facilitam o trabalho do desenvolvedor nas atividades do dia a dia. Clique aqui e conheça um pouco mais sobre esta tecnologia

Sails.js Tech Brasil é um repositório de conhecimento da tecnologia Sails criado e mantido pela RIZ | iko com o propósito de auxiliar a desenvolvedores JavaScript de língua portuguesa na construção de seus produtos e serviços.


JavaScript image
100% JavaScript + HTML5

Sails.js é um projeto de código aberto que mantém o mesmo Mindset, tanto no frontend quanto no backend, facilitando o desenvolvimento de páginas HTML 5 dinâmicas e responsivas.

Database image
Qualquer Banco de Dados

Sails incorpora a tecnologia Waterline cuja implementação ORM, em camadas, permite a conexão com qualquer Banco de Dados, seja Relacional ou Orientado a Documentos.

Um Frontend Agnóstico

Sails permite a utilização de qualquer uma das atuais tecnologias de Frontend, seja Angular, Vue, React ou qualquer outra, mas incorpora nativamente o Vue2-Parasails que viabiliza uma magnífica integração do backend com o frontend


Fácil integração com WebSocket

A tecnologia incorporada ao core do Sails intercepta qualquer requisição WebSocket enviada, permitindo que o desenvolvedor lide com conexões síncronas com facilidade.

Desenvolvimento Rápido
Orientado a Protótipação

Em questão de minutos, você estará navegando no seu primeiro protótipo de aplicação Web e poderá testar:

  • Páginas de Cadastro de Novos Usuários, Login e Logout
  • Funcionalidades para Recuperar e Modificar a Senha
  • Página de FAQ
  • Página de Termos de Serviço
  • Página de Políticas de Uso de Dados
  • Formulário de Solicitação de Suporte
  • Recursos de Internacionalização (i18n)
  • Conexão com um Banco de Dados Local
Desenvolvimento Rápido
Geradores de Código /Scaffolding

Sails disponibiliza um conjunto de geradores de código que implementam funcionalidades 100% JavaScript e seguindo modernos padrões de projeto. Destaca-se:

  • Gerador de Páginas e Rotas
  • Gerador de API RESTFul
  • Gerador de Modelos de Dados
  • Gerador de Funçoes Assíncronas
  • Console integrado para testes em runtime
  • Ferramenta blueprints que facilita a entrada de dados para teste

Modelos Estáticos

O gerador de código do Sails cria vários modelos estáticos que você pode personalizar de acordo com as informações do seu negócio, mas todos os textos estão em inglês e contextualizados para uso nos E.U.A. Nós já traduzimos e contextualizamos estes modelos pra você! São eles:

Páginas Iniciais

O gerador de código do Sails cria várias páginas automaticamente, mas todos os textos estarão em inglês. Nós já traduzimos várias destas páginas pra você! São elas:

Um Protótipo Sails.js deriva todas as páginas de uma principal, a layout.ejs. Se o layout do seu projeto é muito diferente do oferecido pelo framework, utilize este modelo layout vazio pra recomeçar seu Projeto de Tela

Helpers, Hooks, Policies, Scripts & Components

Padronização no uso das funções JavaScript reutilizáveis, atômicas e previsíveis são um dos maiores benefícios do Sails. Desenvolver novas funcionalidades sob esta perspectiva é garantia de sucesso e certeza de que o seu código continuará a ser de fácil manutenção. Nós já compilamos algumas destas facilidades para você! São elas:


Visão Geral

Em termos gerais, Sails.js é um gerador de códigos JavaScript que entrega, em poucos minutos, um protótipo executável de uma Aplicação WEB do tipo backend robusta, segura e escalável. O resultado é a capacidade de entregar páginas HTML5 + CSS + JavaScript dinâmicas ao Cliente Web.

Um protótipo Sails contém:

  1. Páginas de Cadastro de Novos Usuários, Login e Logout
  2. Funcionalidades para Recuperar e Modificar a Senha
  3. Página de FAQ
  4. Página de Termos de Serviço
  5. Página de Políticas de Uso de Dados
  6. Formulário de Solicitação de Suporte
  7. Capacidade nativa de internacionalização (i18n)
  8. Conexão com um Banco de Dados Local

Uma vez que o Protótipo tenha sido gerado, Sails permite ao desenvolvedor:

Sails.js segue o princípio de padrão sobre configuração, onde estão pré-definidos os parâmetros que definirão o seu comportamento, no entanto, se pode alterar praticamente tudo que se desejar por arquivos de configuração. Por exemplo:
- Sails espera encontrar as classe de modelos de dados no diretório src/model e, uma vez criada uma Classe de Modelo, esta pode ser usada para inserir, atualizar, excluir ou ler dados do banco de dados, imediatamente, sem a necessidade de declaração explicita. Esta Classe de Modelo segue o padrão Mapeamento Relacional de Objetos, simplificando a maneira como os desenvolvedores podem criar recursos.
- Sails espera encontrar os Controllers que responderão às requisições HTTP no diretório api/controllers e, uma vez criado um Controllers este é carregado durante a inicialização do sistema e estará disponível como rota.

O Sails tem recursos de segurança integrados que ajudam a proteger as aplicações contra diversos tipos de ataques.

O Sails tem uma comunidade ativa e em crescimento que fornece suporte e recursos para os desenvolvedores.

Como Funciona a Aplicação WEB Gerada ?

  1. Toda a magia começa quando o Navegador (Internet Browser) na estação de trabalho do cliente faz uma requisição (HTTP Request) ao servidor (ex. http://localhost/overview/index.html).
  2. O Core do Sails intercepta a requisição e confronta com as "Políticas de Segurança" definidas no arquivo policies.js , retornando 401 - Forbidden, caso não autorizado.
  3. Uma vez autorizado o acesso, então o Sails compara o "Caminho da Requisição" com as "Rotas" definidas no arquivo routes.js, retornando 404 - Page Not Found, caso não encontre correspondência.
  4. Encontrada a correspondência de "Rota", então o Sails identifica qual é o "Controlador" ( Controllers) associado a esta e o executa para, em princípio, obter os dados que serão expostos na "Visão" que será renderizada em seguida.
  5. Se o "Controlador" contém chamada ao Modelo de Dados, então este aguarda que o Banco de Dados retorne as informações solicitadas para continuar.
  6. Uma vez que os dados tenham sido obtidos, pode então o "Controlador" enviar uma "Resposta" (HTTP Response) ao Navegador. Esta resposta pode ser do tipo JavaScript Object (JSON) ou uma resposta HTML completa.
  7. Se a opção do desenvoledor foi de uma "Resposta HTML", então ele informou qual a "Visão" deve ser "Renderizada" (Ex. action.ejs). Esta visão, por padrão, será do tipo EJS (“Embedded JavaScript Templating”). Você pode, se desejar, modificar o renderizador para qualquer outro compatível com Node.js (em especial com o Express.js). Clique aqui para saber como converter para o renderizador Pug
  8. O Core do Sails orquestrará a passagem dos "Dados Obtidos" pelo "Controlador" para o "Renderizador" EJS, a construção da respectiva página HTML (resultado da renderização), a vinculação com os estilos (CSS Style) e o acoplamento deste HTML gerado com um componente Vue 2 que incorpora o dinamismo JavaScript às páginas HTML.
  9. Visualize este processo no diagrama abaixo
Sails Overview
Clique aqui para seguir um passo de construção de um protótipo
Clique aqui para internacionalizar um protótipo
Helpers, Hooks, Policies & Scripts

Scripts são funções JavaScript que atuam como ferramentas versáteis para execução eventual ou dependente de contexto. Um Script Sails segue o padrão Machinepack (detalhado mais abaixo) e pode ser executado manualmente, na console, ou acionado dentro de um outro artefato Sails.
Utilize:

Policies são funções JavaScript que atuam como ferramentas versáteis para autorização e controle de acesso. Permitem executar alguma lógica antes que uma ação (mapeada no arquivo routes.js) seja executada para determinar se a solicitação deve ou não continuar a processar. O caso de uso mais comum para políticas é restringir determinadas ações apenas a usuários conectados.

Hooks são funções JavaScript que estendem o core Sails adicionando rotas ocultas, ações implícitas e/ou lógica de inicialização. O método "chave" para a inicialização de um Hook deve ser nomeado como initialize()

Helpers são objetos JavaScript estruturados como machinepack controlados pelo core Sails destinados ao uso Global ou repetitivo, ou seja, todos os Helpers são acessíveis por todos os artefatos do Protótipo/Projeto. Uma vez criados, pode-se invocá-los por meio do comando await sails.helpers.nomeHelper.metodo(parametro1, parametro2) ou await sails.helpers.nomeHelper.metodo.with({objeto})

Bootstrap é um inicializador de preparação. O arquivo config/bootstrap.js é executado sempre que a aplicação é inicializada e nele já existem ações pré-definidas relevantes, tais como a identificação do ambiente de execução e criação automática de usuário.

Machinepacks são máquinas para interpretação de funções JavaScript autodocumentáveis e previsíveis que seguem uma especificação, escrita por Mike McNeil.

Como já citado anteriormente, Helpers e Scripts são contruídos conforme a especificação machinepack E NÃO FUNCIONARÃO se forem escritos de outra forma, pois são interpretados pelo core do Sails. Observe que os Hooks e as Policies são funcões JavaScript padrão e não seguem o modelo machinepack.

Helpers devem estar localizados no diretório \api\helpers para que sejam acessíveis em qualquer parte do seu aplicativo.

Hooks devem estar localizados no diretório \api\hooks para que funcionem e serão executados durante a inicialização.

Policies devem estar localizadas no diretório \api\policies para que sejam localizadas pelo core Sails enquanto executa o arquivo de configuracao config/policies.js, durante a inicialização da aplicação.

Scripts devem estar localizadas no diretório \scripts para que sejam localizados pelo core Sails quando acionados pelo comando sails run meu-script, seja manualmente ou por dentro de outro artefato..

Clique aqui para acessar exemplos funcionais que pode utilizar livremente

Inicialização de uma Aplicação Sails

Os seguintes passos são executados pelo core Sails durante a inicialização de uma Aplicação:

  1. São carrregadas as configurações iniciais da Aplicação localizadas nos arquivos: config/datastore.js, config/models.js, config/custom.js, e config/local.j. Este último "local" existe somente na estação de trabalho do desenvolvedor, pois é excluído do controle de versionamento (.git) por padrão e sobrescreve todos os demais, ou seja, havendo repetição de definição, vale a do local.js!
  2. São carregados todos os arquivos do tipo Helper, localizados no diretório api/helpers/*
  3. São carregados e executados todos os arquivos do tipo Hook, localizados no diretório api/hooks/*
  4. É carregado e executado o arquivo config/bootstrap.js
  5. É carregado o arquivo config/sessions.js para identificação dos parâmetros de Sessão do Servidor HTTP
  6. É carregado o arquivo config/http.js para identificação dos parâmetros de Funcionamento do Servidor HTTP
  7. É inicializado o Servidor HTTP
  8. São mapeados os endpoints ou rotas acessíveis por requisições http (localizadas no diretório api/controllers )
  9. É carregado o arquivo config/socket.js para identificação dos parâmetros de Funcionamento do Servidor Web Socket
  10. É inicializado o Servidor Web Socket
  11. Ficam ativos os Listenings de Servidor para a "Escuta" de novas requisições HTTP, até que ocorra um erro ou uma parada intencional.
Cabe destacar que, se for identificado na inicialização que o "Ambiente de Execução" (Environment) contém a variável NODE_ENV=production, então o conteúdo do arquivo config/env/production.js sobregravará as demais definições anteriores, ou seja, havendo repetição de definição, vale a do production.js!
Bootstrap

Actions & Controllers

As ações são responsáveis por responder a solicitações de um navegador ‘web’, aplicativo móvel ou qualquer outro sistema capaz de se comunicar com um servidor. Eles geralmente atuam como um intermediário entre os seus modelos e visões e orquestram a maioria da lógica de negócios do seu projeto. Pode-se usar ações para servir páginas da Web, lidar com envios de formulários, gerir solicitações de API de terceiros e tudo mais. As ações são mantidas nos Controladores.

Controladores são arquivo posicionados no diretório api/controllers/* (e gerenciados pelo core do Sails ) que contém ações no seu corpo.

As ações são vinculadas a rotas em seu aplicativo. Quando um agente do usuário solicita uma URL específica, a ação vinculada a essa rota executa a lógica de negócios e envia uma resposta. Por exemplo, a rota GET /hello em seu aplicativo pode estar vinculada a uma ação como:

                async function (req, res) {
                    return res.send('Olá mundo!');
                }
            
O conhecimento abaixo é extremamente relevante, mas este trabalho pode ser reduzido significativamente pelo uso do recurso Blueprints, nativo no Sails.js!
Clique aqui para saber mais sobre Blueprints

Arquivos de Actions podem ser definidos de duas formas: Action 2 ou Clássico:

Action 2 é o modo mais moderno de se construir Actions no ambiente Sails, no entanto, o modelo Clássico ainda é funcional e, em alguns casos, mais adequado.

Veja abaixo um exemplo de Action 2


            module.exports = {

                friendlyName: 'Church Search',

                description: 'Pesquisa por igrejas estabelecidas em uma determinada cidade.',

                inputs: {
                  nomeCidade: {
                    description: 'o nome da cidade pesquisada.',
                    // Se o valor recebido não for texto, Sails envia um `res.badRequest`, automaticamente
                    type: 'string',
                    // Se o valor esperado não for enviado, Sails envia um `res.badRequest`, automaticamente
                    required: true
                  },
                    // Se multiplas instancias atendem ao requisito, entao paginar sempre sera uma necessidade
                   page: { type: 'number', required: false },
                   size: { type: 'number', required: false }
                },

                exits: {
                  success: {
                    responseType: 'view',
                    viewTemplatePath: 'pages/church/church-search'
                  }
                },

                fn: async function ({nomeCidade, page, size}) {

                 //   Procure igrejas cujo nome da cidade foi especificado na solicitação.
                 //   Observe que não precisamos validar que 'nomeCidade' é um texto;
                 //   o algorítimo da máquina faz isso por nós e retorna 'badRequest'
                 //   se a validação falhar.
                 //   No entanto, sendo page e size opicionais (required: false), melhor garantir que...
                const page = page | 0;
                const size = size | 10;
                var churchs = await Church.find({ cidade: nomeCidade }).skip(page*size).limit(size);
                //    Torna o objeto churchs (neste caso um array) disponivel para uso pela View.EJS
                return {churchs}

                }
              };

              // Atenção: para implementação de todo o CRUD (Create, Read, Update e Delete),
              //          usando Action2, será preciso criar um arquivo 'controller/*.js'
              //          para cada uma das ações. Ex: church-create.js, church-read.js, church-update.js, church-delete.js

        

Veja abaixo um exemplo de Classic Action


/**
 * ChurchController
 *
 * @description :: Server-side actions for handling incoming requests.
 * @help        :: See https://sailsjs.com/docs/concepts/actions
 */

module.exports = {

    read: async function (req, res) {
        // params são obtidos do PATH.
        // Ex.: /api/v1/church/:id
        //      /api/v1/church/32
        const id = req.params['id'];
        await Church.find({id: id})
          .then(
            Church => {
              res.render('pages/church/church-edit', {instance: Church});
            }
          ).catch(err => {
              res.notFound()
              console.log(err.message)
          });
      },

      // query são obtidos dos parametros.
      // Ex.: /api/v1/church?page=0&size=10
      readAll: async function (req, res) {
          const page = req.query.page | 0;
          const size = req.query.size | 0;

         await Church
            .find()
            .skip(page*size)
            .limit(size)
            .then(list => res.view('pages/church/church-search', {list: list}))
            .catch(err => console.log(err.message));

      },

      // body é obtido do corpo das requisições do tipo POST e PUT
      // normalmente JSON ou x-form
      update: async function (req, res) {
        let Church = await Church.find({_id: req.params['id']});
        return res.json(Church.updateOne(
            {
            version: req.body.version,
            description: req.body.description
            }
        ));
      },

      create: async function (req, res) {
        await Church.create(req.body).then(
          Church => res.json(Church)
        ).catch(err => console.log(err));
      },


};
        

Diferença no roteamento de Actions 2 e Clássicos

// Action 2 - Uma acao por arquivo!
'GET /caminho': {action: 'acao'},
// neste caso a função fn ({}) do arquivo api/controllers/acao.js
// Clássico - uma ou mais acoes por arquivo!
'GET /caminho': 'NomeController.get',
// neste caso a função get(req, res) do arquivo api/controllers/NomeController.js
'PUT /caminho': 'NomeController.put',
// neste caso a função put(req, res) do arquivo api/controllers/NomeController.js

        

Captura de Parâmetros Actions 2 e Clássicos


            Para uma rota do tipo:
            POST /altera-texto/num/:num/assunto/:ass/date/:dat?limite={lim}

            Uma requisição:
            POST /altera-texto/num/1/assunto/teste/date/2023-12-30?limite=10
            {
              objeto: { sumario: `Sumario do texto`, detalhe: `Detalhes do texto enviado` }
            }

            teriamos:

            // Action 2:
            inputs: {
               num: {type: 'number', required: true },
               ass: {type: 'string', required: true },
               dat: {type: 'string', required: true },
               limite: {type: 'number', required: false },
               objeto: {type: 'ref', required: false },
            }
            ...
            fn: async function ({num, ass, dat, limite, objeto}){

            const numero = num
            const assunto = ass
            const data = new Date(dat)
            const lim = limite | 0
            const objetoJSON = objeto | { sumario: `-`, detalhe: ''}

            console.log('Sumario: '+objetoJSON.sumario)

            }

            // Classic Action

            fn: async function (req, res){

            const numero = req.param['num']
            const assunto = req.param['ass']
            const dataTexto = new Date(req.param['dat'])
            const limite = req.query.limite | 0
            const objetoJSON = req.body.objeto | { sumario: `-`, detalhe: ''}

            console.log('Sumario: '+objetoJSON.sumario)

            }

            // Observe que para o Action 2, tanto faz se foi um parâmetro de Path (param) ou um Parâmetro do
            // Query do Request (query) ou corpo da requisição (body), tudo será tratado pelo `inputs`.

            // Observe que os valores não obrigatórios (required: false OU ?parametro=valor) devem ser testados,
            // pois podem estar nulos em tempo de execução.

        

Criando Actions

Atenção! Nenhum dos comandos de geração de Actions acima irá adicionar as respectivas rotas dentro dos arquivos config/routes.js.
Se você está utilizando blueprints, o Sails resolve a rota pra você, senão:
Você terá que inserir manualmente!
O Core do Sails.js vai tentar `adivinhar` qual HTTP Method você está tentando criar na sua action2, então, para ajudá-lo, você pode comandar...

Para saber mais:
Início
Images by rawpixel.com