Crie um aplicativo de tarefas em javascript com express, jade e mongodb

Olá a todos, hoje vamos construir um aplicativo de tarefas super simples usando o Express 4 . Express é uma estrutura leve do lado do servidor para node.js. É muito popular, mas não é tão fácil de instalar e rodar com um banco de dados como algo como Rails ou Django.

Neste tutorial, conectaremos um servidor expresso a um banco de dados mongoDB e serviremos nosso html usando o mecanismo de modelagem jade. Para tornar a conversa com o MongoDB mais fácil, usaremos o pacote mongoose npm. Embora o mongodb seja um banco de dados sem esquema (tudo é json), o mongoose nos permite definir modelos e encadear consultas facilmente.

SOURCE CODE está no github aqui

DEMO AO VIVO hospedada por heroku está aqui

Configure o projeto

Ao contrário do Ruby On Rails, o express permite que você configure sua estrutura de arquivos da maneira que desejar. Isso era confuso para mim ao olhar para o código de outras pessoas, porque eu não tinha certeza de qual era a melhor maneira de organizar meu projeto. Esta é a estrutura de diretório que vou usar hoje:

express-todo
|- config
|- public
|- javascripts
|- stylesheets
|- images
|- routes
|- views
.gitignore
package.json
server
.js
README
.md

public – esta pasta conterá arquivos que todos podem ver ao visitar nossa página com um navegador da web. Aqui é onde colocaremos javascript e css do lado do cliente.

config – aqui vamos ter tudo a ver com a configuração de nossos ambientes e gerenciamento de nosso banco de dados

rotas – é aqui que teremos a lógica do aplicativo do lado do servidor. Se você tem experiência com trilhos, você pode pensar neles como controladores

visualizações – nossos modelos de jade estão aqui

package.json – define todos os pacotes (como express e mongoose) dos quais nosso aplicativo depende

server.js – este é o principal arquivo executável para tudo. Para executar nosso aplicativo, vamos executar node serverou a partir da linha de comando (terminal no mac). Se algo não funcionar, comece aqui.node server.js

Construir um servidor

Ok, agora vamos começar a codificação! Vamos começar, mas executando nosso arquivo server.js para ouvir acessos a uma porta específica em nossos computadores. Com este arquivo, executaremos um servidor web local em nosso computador. Posteriormente, implantaremos isso como um servidor web real para as interwebs.

var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var port = 3000;

var app = express();

// view engine setup
app
.set('views', path.join(__dirname, 'views'));
app
.set('view engine', 'jade');

//app.use(favicon(__dirname + '/public/favicon.ico'));
app
.use(logger('dev'));
app
.use(bodyParser.json());
app
.use(bodyParser.urlencoded());
app
.use(cookieParser());
// telling Express to serve static objects from /public
app
.use(express.static(path.join(__dirname, 'public')));

// Start server
app
.listen(port, function(){
console
.log('Server listening on port ' + port)
});

Primeiro dizemos ao express onde encontrar nossos modelos (ou seja, o diretório de visualizações) e depois dizemos ao express para usar o jade como nosso mecanismo de modelo. body-parser é para lidar com entradas de formulários. Cookies que não usaremos, mas incluí mesmo assim. A próxima linha diz ao express de onde servir ativos estáticos, de forma que todo o código do nosso servidor não fique visível para todos.

Você pode verificar se este código funciona executando node serverna linha de comando. Você deve obter “O servidor está ouvindo na porta 3000”. Em seguida, verifique em seu navegador da web e você verá um errolocalhost:3000

“Não consegue ter /”

Isso ocorre porque não definimos nenhuma rota.

Defina nossas rotas

As rotas são essencialmente urls para o seu site. Então, quando você foi a, você visitou a raiz base . Para o nosso site, queremos rotas para visualizar, criar e editar todos. Portanto, modifique server.js após a linha express.static e antes de app.listen.localhost:3000/

// Routes
var main = require('./routes/main');
var todo = require('./routes/todo');
var todoRouter = express.Router();
app
.use('/todos', todoRouter);

app
.get('/', main.index);
todoRouter
.get('/', todo.all);
todoRouter
.post('/create', todo.create);
todoRouter
.post('/destroy/:id', todo.destroy);
todoRouter
.post('/edit/:id', todo.edit);

Crie também dois arquivos, main.js e todo.js, na pasta de rotas. Antes de entrar nesses arquivos, vamos examinar as novas rotas expressas que definimos. O usuário pode visitar nossa página inicial /, eles serão capazes de ver todas as tarefas em , criar tarefas enviando uma solicitação de postagem para e excluir todas enviando uma solicitação de exclusão para . Este será o ID exclusivo do banco de dados fornecido a nós por mongodb. Finalmente, eles poderão atualizar todos enviando uma solicitação put para e visualizar todos os pendências individuais em ./todos/todos/create/todos/destroy/:id:id/todos/edit/:id/todos/:id

Cada um desses cenários será tratado com uma função que leva dois parâmetros – solicitação e resposta.

Defina as funções do manipulador de tarefas em routes / todo.js com algum conteúdo vazio por enquanto:

module.exports = {
all
: function(req, res){
res
.send('All todos')
},
viewOne
: function(req, res){
console
.log('Viewing ' + req.params.id);
},
create
: function(req, res){
console
.log('Todo created')
},
destroy
: function(req, res){
console
.log('Todo deleted')
},
edit
: function(req, res){
console
.log('Todo ' + req.params.id + ' updated')
}
};

Portanto, neste arquivo, temos um objeto com chaves e funções de manipulador como valores. torna o objeto neste arquivo utilizável em nosso arquivo server.js. obtém o valor diretamente da barra de url. Tente visitar em seu navegador. As mensagens console.log serão desconectadas em seu terminal e você verá “Exibindo blahblahblah”.module.exportsreq.params.idlocalhost:3000/todos/blahblahblah

Ficando cansado

Vamos configurar a página inicial. Em nosso server.js esta linha lida com nossa homepage. Defina a função do controlador em routes / main.js:app.get('/', main.index);

module.exports = {
index
: function(req, res) {
res
.render('main', { title: 'Express Todo' });
}
};

res.renderrenderiza uma visualização. Já dissemos que expressar nossas opiniões estão na viewspasta e que estamos usando modelos de jade. Crie um arquivo main.jade :

extends layout

block content

h1
= title
p
Welcome to #{title}
a
(href='/todos').btn.btn-success.btn-lg View all todos

E também crie um layout.jade na pasta de visualizações:

doctype html
html

title
Express Todo
link
(rel="stylesheet", href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css")
link
(rel="stylesheet", href="/stylesheets/main.css")
body

block content

Aqui, incluímos o link cdn de bootstrap do Twitter para estilização. Clique no grande botão verde e você navegará até . Tenha cuidado para não misturar tabulações e espaços em seu código jade. Você tem que usar um ou outro ou a Sra. Jade fica com raiva/todos

Adicionar MongoDB

Agora que nosso servidor está funcionando e fornecendo conteúdo, vamos conectá-lo a um banco de dados local. Primeiro adicione o mangusto como uma dependência. Então, do terminal:

$ npm install mongoose --save

Verifique também se você instalou o mongodb . Abra um novo terminal e execute$ mongo --version

$ mongod

Isso ativa o MongoDB e permite que ele opere. Para se conectar a um banco de dados mongodb local, o mongod deve estar em execução.

Em outra janela de terminal, insira $ mongovamos criar um banco de dados mongodb local:

$ mongo
MongoDB shell version: 2.6.4
connecting to
: test
Server has startup warnings:
2014-12-24T10:30:36.556-0800 [initandlisten]
2014-12-24T10:30:36.556-0800 [initandlisten] ** WARNING: soft rlimits too low. Number of files is 256, should be at least 1000
>

Neste tipo de REPL para criar nosso banco de dados local. Para ver todos os bancos de dados que você possui, digite . Para sair do terminal mongo, pressione Ctrl + Cuse express-todoshow dbs

Definir modelo de dados e conectar

Mesmo que mongodb não tenha esquema, para modelar nossos dados com mongoose ainda precisamos definir modelos. Crie uma nova pasta dentro de configuração chamado modelos e adicionar um novo arquivo chamado Todo.js . Em seguida, definiremos como serão os nossos dados de tarefas com um esquema:

var mongoose = require('mongoose'),
Schema = mongoose.Schema;

// todo model
var todoSchema = new Schema({
content
: String,
completed
: { type: Boolean, default: false },
updated_at
: { type: Date, default: Date.now }
});

mongoose
.model('Todo', todoSchema);

Em seguida, em server.js, adicione este código acima do código para as rotas:

require('./config/models/Todo');
mongoose
.connect('mongodb://localhost/express-todo', function(){
console
.log('connected to database!')
});

Isso registra nosso esquema de tarefas e se conecta ao banco de dados mongodb local.

Mostrar todos

Mesmo que nosso banco de dados esteja vazio, vamos consultá-lo. Atualize o código em :routes/todo.js

var mongoose = require('mongoose'),
Todo = mongoose.model('Todo');

module.exports = {
all
: function(req, res){
Todo.find({}, function(err, todos){
if(err) res.send(err);
res
.json(todos);
})
}
...

Aqui, incluímos o modelo Todo que registramos anteriormente, consultamos todas as entradas (o primeiro parâmetro é opcional aqui) e respondemos com JSON para a página da web.

Se você visitar, deverá ver um array vazio na páginalocalhost:3000/todos

Criando todos

Crie um arquivo de visualização chamado todos.jade no qual exibiremos todos os todos.

extends layout

block content

h1
.text-center All Todos
ul

for todo in todos
li
#{todo.content}
form
(method='post', action='/todos/create')
.input-group
input
.form-control(type='text', placeholder='What do you have to do?', name='content')
span
.input-group-btn
input
.btn.btn-success(type='submit', value='Add Todo')

Aqui temos uma lista não ordenada para exibir os todos e um formulário que chega ao nosso servidor com uma solicitação de postagem para adicionar um.

Vamos definir a rota que o formulário atinge. Aberto . Aqui está o código para criar uma tarefa e recarregar a página.routes/todo.js

...
create
: function(req, res){
var todoContent = req.body.content;
// create todo
Todo.create({ content: todoContent }, function(err, todo){
if(err) res.render('error', { error: 'Error creating your todo :('})
// reload collection
res
.redirect('/todos');
});
},
...

Parabéns! Agora você tem um servidor javascript que pode se comunicar com um banco de dados e processar as informações em um navegador da web

Excluindo todos

Primeira atualização todos.jade

block content
h1
.text-center All Todos
.panel.panel-default
for todo in todos
.panel-body
a
(href='/todos/#{todo._id}') #{todo.content}
form
(action='/todos/destroy/#{todo._id}', method='post')
input
.btn.btn-danger.pull-right(type='submit', value='Delete')

Para isso, apresentamos um formulário ao pressionar o botão. O estilo não é perfeito, mas você pode mexer nele como quiser.

Este é o código para excluir uma tarefa e recarregar a página:

destroy: function(req, res){
var id = req.params.id;

Todo.findByIdAndRemove(id, function(err, todo){
if(err) res.render('error', { error: 'Error deleting todo'});
res
.redirect('/todos');
});
},

Ver e atualizar todos

Gostaria que cada tarefa tivesse sua própria página e pudesse editar as tarefas nessa página. Crie um arquivo todo.jade no diretório de visualizações:

extends layout

block content

form
(method='post', action='/todos/edit/#{todo._id}')
h1

input
(value='#{todo.content}', name='content')
input
(type='submit', value='Update').btn.btn-primary.btn-lg
a
(href='/todos').btn.btn-default.btn-lg Back

Isso estende o layout novamente e tem um formulário para atualização e também um botão Voltar. Aqui estão os métodos para visualizar a página e lidar com a solicitação de atualização. (Nós os redirecionamos de volta para a lista completa após a conclusão da atualização.)

viewOne: function(req, res){
Todo.find({ _id: req.params.id }, function(err, todo){
res
.render('todo', { todo: todo[0] })
});
},
edit
: function(req, res){
Todo.findOneAndUpdate({ _id: req.params.id }, {content: req.body.content}, function(err, todo){
res
.redirect('/todos');
});
}

Agora temos uma página para mostrar todos os todos e também cada um tem sua própria página com seu próprio url exclusivo. Também podemos adicionar, excluir e atualizar todos os nossos todos.

Refatorar

Nosso código até agora não funcionará em produção porque estamos lendo de um banco de dados local. Além disso, o arquivo server.js tem um monte de coisas jogadas nele e não precisa ser tão pesado. Vamos limpar isso.

Novo arquivo server.js :

var express = require('express');