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 final é a capacidade de entregar páginas HTML5 + CSS + JavaScript dinâmicas ao Cliente Web.
Se esta é sua primeira vez aqui, recomendamos a leitura dos conteúdos abaixo antes de continuar:
npm i sails -g
sails new primeiro-prototipo
Choose a template for your new Sails app: 1. Web App · Extensible project with auth, login, & password recovery 2. Empty · An empty Sails app, yours to configure (type "?" for help, or <CTRL+C> to cancel) ? 1
cd primeiro-prototipo
npm i axios --save
para uso do protótiposails lift
você verá:
info: Starting app... info: Initializing project hook... (`api/hooks/custom/`) info: Initializing `apianalytics` hook... (requests to monitored routes will be logged!) info: ·• Auto-migrating... (alter) info: Hold tight, this could take a moment. info: ✓ Auto-migration complete. debug: Running v0 bootstrap script... (looks like this is the first time the bootstrap has run on this computer) info: info: .-..-. info: info: Sails <| .-..-. info: v1.5.8 |\ info: /|.\ info: / || \ info: ,' |' \ info: .-'.-==|/_--' info: `--'-------' info: __---___--___---___--___---___--___ info: ____---___--___---___--___---___--___-__ info: info: Server lifted in `C:\Users\rogeriorfs\git\passo-a-passo` info: To shut down Sails, press <CTRL> + C at any time. info: Read more at https://sailsjs.com/support. debug: ------------------------------------------------------- debug: :: Mon Jul 17 2023 08:15:43 GMT-0300 (Horário Padrão de Brasília) debug: Environment : development debug: Port : 1337 debug: Local : http://localhost:1337 debug: ------------------------------------------------------->
http://localhost:1337
.
O navegador deve aprsentar algo do tipo:
sails generate page
lista-tarefas
Successfully generated: •- views\pages\lista-tarefas.ejs •- api\controllers\view-lista-tarefas.js •- assets\styles\pages\lista-tarefas.less •- assets\js\pages\lista-tarefas.page.js A few reminders: (1) These files were generated assuming your Sails app is using Vue.js as its front-end framework. (If you're unsure, head over to https://sailsjs.com/support) (2) You'll need to manually add a route for this new page's action in your `config/routes.js` file; e.g. 'GET /lista-tarefas': { action: 'view-lista-tarefas' }, (3) You'll need to manually import the new LESS stylesheet from your `assets/styles/importer.less` file; e.g. @import 'pages/lista-tarefas.less'; (4) Last but not least, since some of the above are backend changes, don't forget to re-lift the server before testing!
config/routes.js
a linha 'GET
/lista-tarefas': { action: 'view-lista-tarefas' },
views/pages/dashboard/welcome.ejs
e adicione
<a class="btn btn-info" href="/lista-tarefas">Minha Lista de Tarefas</a>
admin@example.com
senha abc123
<- GET /login (6ms 200) | view: pages/entrance/login ° <- PUT /api/v1/entrance/login (226ms 200) | The requesting user agent has been successfully logged in. | | Under the covers, this stores the id of the logged-in user in the session as the `userId` key. The next time this user agent sends a request, assuming it includes a cookie (like a web browser), Sails will automatically make this user id available as req.session.userId in the corresponding action. (Also note that, thanks to the included "custom" hook, when a relevant request is received from a logged-in user, that user's entire record from the database will be fetched and exposed as `req.me`.) | ° <- GET / (3ms 302) | redirect | Requesting user is logged in, so redirect to the internal welcome page. ° <- GET /welcome (6ms 200) | Display the welcome page for authenticated users. | view: pages/dashboard/welcome ° <- POST /api/v1/observe-my-session (2ms 200) | The requesting socket is now subscribed to socket broadcasts about the logged-in user's session. ° <- GET /lista-tarefas (6ms 200) | view: pages/lista-tarefas °
sails generate model tarefa
info: Created a new model ("Tarefa")!
api/models
e você deverá encontrar um arquivo
api/models/Tarefa.js
com o seguinte conteúdo:
/** * Tarefa.js * * @description :: A model definition represents a database table/collection. * @docs :: https://sailsjs.com/docs/concepts/models-and-orm/models */ module.exports = { attributes: { // ╔═╗╦═╗╦╔╦╗╦╔╦╗╦╦ ╦╔═╗╔═╗ // ╠═╝╠╦╝║║║║║ ║ ║╚╗╔╝║╣ ╚═╗ // ╩ ╩╚═╩╩ ╩╩ ╩ ╩ ╚╝ ╚═╝╚═╝ // ╔═╗╔╦╗╔╗ ╔═╗╔╦╗╔═╗ // ║╣ ║║║╠╩╗║╣ ║║╚═╗ // ╚═╝╩ ╩╚═╝╚═╝═╩╝╚═╝ // ╔═╗╔═╗╔═╗╔═╗╔═╗╦╔═╗╔╦╗╦╔═╗╔╗╔╔═╗ // ╠═╣╚═╗╚═╗║ ║║ ║╠═╣ ║ ║║ ║║║║╚═╗ // ╩ ╩╚═╝╚═╝╚═╝╚═╝╩╩ ╩ ╩ ╩╚═╝╝╚╝╚═╝ }, };
api/models/Tarefa.js
e adicione os campos: prioridade, descricao e prazo,
do
seguinte modo:
/** * Tarefa.js * * @description :: A model definition represents a database table/collection. * @docs :: https://sailsjs.com/docs/concepts/models-and-orm/models */ module.exports = { attributes: { // ╔═╗╦═╗╦╔╦╗╦╔╦╗╦╦ ╦╔═╗╔═╗ // ╠═╝╠╦╝║║║║║ ║ ║╚╗╔╝║╣ ╚═╗ // ╩ ╩╚═╩╩ ╩╩ ╩ ╩ ╚╝ ╚═╝╚═╝ prioridade: {type: 'number', required: true, description: 'Registra a prioridade de atendimento'}, descricao: {type: 'string', required: true, description: 'Registra o que deve ser feito'}, prazo: {type: 'string', columnType: 'date', required: false, description: 'Data limite, se existir'}, // ╔═╗╔╦╗╔╗ ╔═╗╔╦╗╔═╗ // ║╣ ║║║╠╩╗║╣ ║║╚═╗ // ╚═╝╩ ╩╚═╝╚═╝═╩╝╚═╝ // ╔═╗╔═╗╔═╗╔═╗╔═╗╦╔═╗╔╦╗╦╔═╗╔╗╔╔═╗ // ╠═╣╚═╗╚═╗║ ║║ ║╠═╣ ║ ║║ ║║║║╚═╗ // ╩ ╩╚═╝╚═╝╚═╝╚═╝╩╩ ╩ ╩ ╩╚═╝╝╚╝╚═╝ }, };
sails lift
e, se nenhuma mensagem de erro aparecer, passe para a
etapa
seguinte.admin@example.com
e senha
abc123
http://localhost:1337/tarefa/create?prioridade=1&descricao=Teste&prazo=2023-07-12T14:27:20.992Z
.tmp/localDiskDb/tarefa.db
e verifique se seus dados criados
acima já
aparecem na coleção tarefa.db
. Espera-se que o arquivo agora contenha algo do tipo:
{"$$indexCreated":{"fieldName":"id","unique":true,"sparse":false}} {"prioridade":1,"descricao":"Teste","prazo":"2023-07-12T14:27:20.992Z","createdAt":1689172040992,"updatedAt":1689172040992,"id":1,"_id":1}
views/layouts/layout.ejs
a seguinte linha
<script src="https://unpkg.com/axios@1.1.2/dist/axios.min.js"></script>
assets/js/pages/lista-tarefas.page.js
para que ele
obtenha, por requisições RESTful, os objetos disponibilizados pelo Controller, conforme abaixo:
parasails.registerPage('lista-tarefas', { // ╦╔╗╔╦╔╦╗╦╔═╗╦ ╔═╗╔╦╗╔═╗╔╦╗╔═╗ // ║║║║║ ║ ║╠═╣║ ╚═╗ ║ ╠═╣ ║ ║╣ // ╩╝╚╝╩ ╩ ╩╩ ╩╩═╝ ╚═╝ ╩ ╩ ╩ ╩ ╚═╝ data: { tarefas: [] }, // ╦ ╦╔═╗╔═╗╔═╗╦ ╦╔═╗╦ ╔═╗ // ║ ║╠╣ ║╣ ║ ╚╦╝║ ║ ║╣ // ╩═╝╩╚ ╚═╝╚═╝ ╩ ╚═╝╩═╝╚═╝ beforeMount: function() { /* captura as variaveis / objetos da sessao */ /* e atribui a este objeto 'this'. */ /* Deste modo, o Vue2 pode acessar a lista */ /* de {tarefas} obtida no BD pelo Controller. */ _.extend(this, window.SAILS_LOCALS); }, mounted: async function() { const response = await axios.get('/tarefa/find') this.tarefas = response.data }, // ╦╔╗╔╔╦╗╔═╗╦═╗╔═╗╔═╗╔╦╗╦╔═╗╔╗╔╔═╗ // ║║║║ ║ ║╣ ╠╦╝╠═╣║ ║ ║║ ║║║║╚═╗ // ╩╝╚╝ ╩ ╚═╝╩╚═╩ ╩╚═╝ ╩ ╩╚═╝╝╚╝╚═╝ methods: { //… } });
views/pages/lista-tarefas.ejs
, conforme abaixo:
<div class="container" id="lista-tarefas" v-cloak> <p>Listagem montada no frontend pelo Vue 2 (a partir da resposta ao HTTP GET /tarefa/find)</p> <ol> <li v-for='tarefa in tarefas'>{{tarefa.descricao}}</li> </ol> </div> <%- /* Expose server-rendered data as window.SAILS_LOCALS :: */ exposeLocalsToBrowser() %>
sails lift
, faça login e e navegue para sua Lista de
Tarefas (conforme orientado acima).
sails generate page
edit-tarefas
config/routes.js
a
seguinte linha
'GET /edit-tarefas': { action: 'view-edit-tarefas' },
'GET /edit-tarefas/:id': { action: 'view-edit-tarefas' },
api\controllers\view-edit-tarefas.js
para que tenha o
seguinte
conteúdo:
module.exports = { friendlyName: 'View edit tarefas', description: 'Display "Edit tarefas" page.', inputs: { id: {type: 'string', required: true} }, exits: { success: { viewTemplatePath: 'pages/edit-tarefas' } }, fn: async function ({id}) { const axios = require('axios') const response = await axios.get(`/tarefa/${id}`) let instance = response.data return {instance}; } };
assets\js\pages\edit-tarefas.page.js
para que tenha o seguinte
conteúdo:
parasails.registerPage('edit-tarefas', { // ╦╔╗╔╦╔╦╗╦╔═╗╦ ╔═╗╔╦╗╔═╗╔╦╗╔═╗ // ║║║║║ ║ ║╠═╣║ ╚═╗ ║ ╠═╣ ║ ║╣ // ╩╝╚╝╩ ╩ ╩╩ ╩╩═╝ ╚═╝ ╩ ╩ ╩ ╩ ╚═╝ data: { tarefa: {}, prazo: new Date(), }, // ╦ ╦╔═╗╔═╗╔═╗╦ ╦╔═╗╦ ╔═╗ // ║ ║╠╣ ║╣ ║ ╚╦╝║ ║ ║╣ // ╩═╝╩╚ ╚═╝╚═╝ ╩ ╚═╝╩═╝╚═╝ beforeMount: function() { /* captura as variaveis / objetos da sessao */ /* e atribui a este objeto 'this'. */ /* Deste modo, o Vue2 pode acessar a lista */ /* de {tarefas} obtida no BD pelo Controller, */ /* mas neste caso, vamos explicitar uma outra */ /* entidade tarefa simplesmente para */ /* faciltiar a compreensao do codigo. */ _.extend(this, window.SAILS_LOCALS); this.tarefa = this.instance; this.prazo = new Date(this.tarefa.prazo); }, mounted: async function() { //… }, // ╦╔╗╔╔╦╗╔═╗╦═╗╔═╗╔═╗╔╦╗╦╔═╗╔╗╔╔═╗ // ║║║║ ║ ║╣ ╠╦╝╠═╣║ ║ ║║ ║║║║╚═╗ // ╩╝╚╝ ╩ ╚═╝╩╚═╩ ╩╚═╝ ╩ ╩╚═╝╝╚╝╚═╝ methods: { /* Este metodo utiliza o recurso Blueprints do Sails.js */ */ save: async function(tarefa) { let result = await axios.post('/tarefa', tarefa) alert(JSON.stringify(result)); window.location.reload() } } });
views/pages/edit-tarefas.ejs
para que tenha o seguinte conteúdo:
<div id="edit-tarefas" class="container" v-cloak="" > <div class="display-3">Manipulação dos dados com Vue</div> <input type="hidden" name="_csrf" id="_csrf" value="<%=_csrf%>"> <label for="prioridade">Prioridade</label> <input type="number" class="form-control" id="prioridade" name="prioridade" v-model="tarefa.prioridade" required> <label for="descricao">Descrição</label> <input type="text" class="form-control" id="descricao" name="descricao" v-model="tarefa.descricao" required> <label for="prazo">Prazo</label> <input type="date" class="form-control" id="prazo" name="prazo" v-model="prazo"> <button class="btn btn-primary mt-2" @click="save(tarefa)">Enviar</button> <div class="display-3">Visualização dos dados com EJS</div> <label for="pri">Prioridade</label> <span class="form-control" id="pri"><%=instance.prioridade%></span> <label for="des">Descricao</label> <span class="form-control" id="des"><%=instance.descricao%></span> <label for="praz">Prazo</label> <span class="form-control" id="praz" ><%=new Date(instance.prazo).toLocaleDateString()%></span> </div> <%- /* Expose server-rendered data as window.SAILS_LOCALS :: */ exposeLocalsToBrowser() %>
/views/pages/lista-tarefas.ejs
para que tenha o seguinte
conteúdo:
<div id="lista-tarefas" v-cloak> <p>Listagem montada no frontend pelo Vue 2 (a partir do window.SAILS_LOCALS)</p> <ol> <li v-for='tarefa in tarefas'><a v-bind:href="'/edit-tarefas/'+tarefa.id" >{{tarefa.descricao}}</a></li> </ol> <p>Listagem montada no backend pela renderização do template EJS (passagem de parametros pelo <em>Enginer</em> Sails</p> <ol> <% tarefas.forEach(tarefa=>{ %> <li><a href="/edit-tarefas/<%=tarefa.id%>"><%=tarefa.descricao%></a></li> <% }) %> </ol> </div> <%- /* Expose server-rendered data as window.SAILS_LOCALS :: */ exposeLocalsToBrowser() %>
sails lift
, faça login e navegue até sua listagem de
tarefas. Você provavelmente visualizará algo do tipo:
sails
lift
, fazer o login, navegar até a lista de tarefas, selecionar uma tarefa para edição,
modificar os dados e clicar no botão [Enviar].
.tmp/localDiskDb/tarefa.db
(ou simplesmente volte para a 'listagem de
tarefas') e verifique se os dados foram alterados.Em aproximadamente 30 minutos...
sails new nome-prototipo
;cd nome-prototipo
;sails lift
e navega para
http://localhost:1337
;
admin@example.com
e abc123
;
sails generate page nome-da-pagina
e
adiciona a rota no arquivo config/routes.js
;
sails generate action nome-action
sails
generate model nome-modelo
;
sails lift