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.
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.
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.
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
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.
Em questão de minutos, você estará navegando no seu primeiro protótipo de aplicação Web e poderá testar:
Sails disponibiliza um conjunto de geradores de código que implementam funcionalidades 100% JavaScript e seguindo modernos padrões de projeto. Destaca-se:
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:
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
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:
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:
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.
policies.js
, retornando 401 - Forbidden, caso não autorizado.
routes.js
, retornando 404 - Page Not Found, caso não encontre
correspondência.
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:
sails generate script meu-script
- para criar um novo Script como /scripts/meu-script.js
sails run meu-script
- para executar o Script no terminal (shell), a partir da raiz do protótipoawait require('<path relativo>/scripts/meu-script').fn()
- para executar o Script dentro de outro artefato. Ex. dentro do
/config/bootstrap.js
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..
Os seguintes passos são executados pelo core Sails durante a inicialização de uma Aplicação:
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!
api/helpers/*
api/hooks/*
config/bootstrap.js
config/sessions.js
para identificação dos parâmetros de Sessão do
Servidor HTTP
config/http.js
para identificação dos parâmetros de Funcionamento do
Servidor HTTP
api/controllers
)
config/socket.js
para identificação dos parâmetros de Funcionamento
do
Servidor Web Socket
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!
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!'); }
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
sails generate action nome-da-action
;sails generate page nome-da-page
.
Neste caso será criado um arquivo controllers/view-nome-da-page.js
,
um outro views/pages/nome-da-page.ejs
e
outro assets/js/pages/nome-da-page.page.js
(Vue 2);
sails generate controller nome-do-arquivo
e adicionar as actions dentro dele manualmente;
sails generate api nomemodel
.
Neste caso, serão criados: controllers/NomemodelController.js
e models/Nomemodel.js
.
Recomenda-se implementar 5 funções para os 5 métodos padrão RESTful: get, post, put, path e delete.
(ou deixe como está e ative a ferramenta Rotas Blueprints RESTful )
config/routes.js
.