Node.js para leigos – Framework Express Parte 2

Mini curso de Node.js para leigos


Dando continuidade ao nosso mini-cursinho e especificamente voltando ao assunto sobre o framework ExpressJS, hoje apresentarei mais dicas sobre como desenvolver uma aplicação web com esse incrível módulo.
No post anterior explicamos a essência, que na prática apresentei uma aplicação funcional, um mini-cadastro de clientes explorando as boas práticas de desenvolvimento orientado à arquitetura REST, utilizando os principais métodos do protocolo HTTP (GET, POST, PUT e DELETE) isso tudo no primeiro post hein!

Otimizando a nossa aplicação neste post incluiremos novos recursos: inclusão de novas configurações no servidor da aplicação, separação de código HTML do código Server-Side, aplicação de filtros.

Obs.: Para executar com sucesso o código abaixo, será necessário incluir um novo framework responsável por renderização de HTML dinâmico com Node.js, o EJS.


npm install ejs


Mãos a obra! Confira abaixo a versão do código antigo já com algumas otimizações pra explicar:

var express = require('express');
var app = express.createServer(); 

app.configure(function(){
    app.set('views', __dirname + '/views');
    app.set('view engine', 'ejs');
    app.set('view options', {layout: false});
    app.use(express.bodyParser());
    app.use(express.methodOverride());
});

var clientes = [];

app.get('/', function(req, res){
    res.render('index', {clientes: clientes});
});

app.post('/cliente', function(req, res){
    var cliente = req.body.cliente;
    clientes.push(cliente);
    res.redirect('/');
});

app.get('/cliente/:id/editar', function(req, res){
    var id = req.params.id;
    res.render('edit', {cliente: clientes[id]});
});

app.put('/cliente/:id', function(req, res){
    var id = req.params.id;
    clientes[id] = req.body.cliente;
    res.redirect('/');
});

app.del('/cliente/:id', function(req, res){
    var id = req.params.id;
    delete clientes[id];
    res.redirect('/');
});

app.listen(3000);

Reparem no quão clean ficou o código do server-side da aplicação, simplesmente separando código html do javascript, e melhorando o dinamismo de manipulações html, utilizamos o EJS como framework template engine, com isso incluiremos as páginas com extensões .ejs (index.ejs e edit.ejs) no subdiretório chamado views.
Tudo isso com incluindo 3 novos parâmetros no callback da função app.configure():

app.set('views', __dirname + '/views'); // Informa o subdiretório das views. 
app.set('view engine', 'ejs'); // Informa o template engine de renderização das views (Framework EJS)
app.set('view options', {layout: false}); // Manipula layouts, o EJS não possui esse recurso então deixe false.

Abaixo mostrarei como ficarão as views index.ejs e edit.ejs que são referenciadas em algumas rotas da aplicação, através do método: res.render(‘nome_da_view’, {variaveis para renderização no cliente});
View: index.ejs

<html>
    <body>
         <h1>Cadastro de cliente</h1>
         <form action="/cliente" method="post">
             <label>Nome: <input type="text" name="cliente[nome]"></label><br>
             <label>Idade: <input type="text" name="cliente[idade]"></label><br>
             <button type="submit">Enviar</button>
         </form>
         <h1>Lista de clientes</h1>
         <ul>
            <% for(var i = 0; i < clientes.length; i++){ %>
                <li><%= clientes[i].nome %> - <%= clientes[i].idade %><a href="/cliente/<%= i %>/editar">Editar</a> | <a href="/cliente/<%= i %>">Excluir</a></li>
            <% } %>
        </ul>
    </body>
</html>

View: edit.ejs

<html>
    <body>
        <h1>Editar dados do cliente: <%= cliente.nome %></h1>
        <form action="/cliente" method="post">
            <input type="hidden" name="_method" value="put">
            <label>Nome: <input type="text" name="cliente[nome]" value="<%= cliente.nome %>"></label><br>
            <label>Idade: <input type="text" name="cliente[idade]" value="<%= cliente.idade %>"></label><br>
            <button type="submit">Enviar</button>
        </form>
    </body>
</html>

Pronto, agora temos em nossa aplicação o html separado dos arquivos js, e isso além de organizar seus códigos facilita na manutenção do mesmo.
Agora pense comigo, o que acontecerá se eu cadastrar um cliente em branco? Seria legal adicionarmos um filtro para tratar os dados de forma que lance um erro caso tente cadastrar com dados em branco, e será isso que faremos!
Antes das rotas da aplicação, adicionaremos a seguinte rotina para renderizar uma tela de erros:

app.use(function(req, res, next){
    res.render('404', {status: 404});
});
app.error(function(err, req, res, next){
    res.render('500', {status: 500, error: err});
});

Com isso teremos que criar duas páginas uma com o nome 404.ejs e a outra 500.ejs, em que elas irão renderizar mensagens de erros do sistema.
404.ejs

<html>
    <head>
         <title>Página não encontrada.</title>
    </head>
    <body>
         <h1>Página não encontrada.</h1>
    </body>
</html>

500.ejs

<html>
    <head>
         <title>Erro na aplicação.</title>
    </head>
    <body>
         <h1>Erro na aplicação.</h1>
         <h3>Detalhes: <%= error.message %></h3>
    </body>
</html>

Agora com toda estrutura para tratamento de erros pronto, precisamos criar uma regra de tratamento sobre os campos do cliente, que na prática serão incluídos funções de filtros para serem realizadas antes da execução de uma determinada rota. Para se fazer isso no Express, qualquer rota que incluir a declaração de uma função como callback antes da função principal da rota será considerado como filtro que executa antes da rota principal, veja o exemplo abaixo…

// Qualquer função que receber os três paramêtros abaixo, serão consideradas como funções de filtros pelo Express.
var validarCampos = function(req, res, next){
    if(req.body.cliente.nome){
        return next(new Error('Informe o nome do cliente.'));
    }
    if(req.body.cliente.idade){
        return next(new Error('Informe a idade do cliente.'));
    }
    return next();
}
// Agora basta incluir a declaração da função validarCampos antes do callback de execução da rota.
app.post('/cliente', validarCampos, function(req, res){
    var cliente = req.body.cliente;
    clientes.push(cliente);
    res.redirect('/');
});

app.put('/cliente/:id', validarCampos, function(req, res){
    var id = req.params.id;
    clientes[id] = req.body.cliente;
    res.redirect('/');
});

Esse foi um exemplo simples de tratamento de erros, na prática recomendo que utilize-o para tratamentos complexos, visto que esse exemplo de validação de campos é apenas um exemplo hipotético de como explorar os redirecionamentos de páginas de erros.
Para facilitar veja abaixo como ficou o nosso código back-end da aplicação:

var express = require('express');
var app = express.createServer(); 

app.configure(function(){
    app.set('views', __dirname + '/views');
    app.set('view engine', 'ejs');
    app.set('view options', {layout: false});
    app.use(express.bodyParser());
    app.use(express.methodOverride());
});

var clientes = [];

var validarCampos = function(req, res, next){
    if(req.body.cliente.nome){
        return next(new Error('Informe o nome do cliente.'));
    }
    if(req.body.cliente.idade){
        return next(new Error('Informe a idade do cliente.'));
    }
    return next();
}

app.use(function(req, res, next){
    res.render('404', {status: 404});
});
app.error(function(err, req, res, next){
    res.render('500', {status: 500, error: err});
});

app.get('/', function(req, res){
    res.render('index', {clientes: clientes});
});

app.post('/cliente', validarCampos, function(req, res){
    var cliente = req.body.cliente;
    clientes.push(cliente);
    res.redirect('/');
});

app.get('/cliente/:id/editar', function(req, res){
    var id = req.params.id;
    res.render('edit', {cliente: clientes[id]});
});

app.put('/cliente/:id', validarCampos, function(req, res){
    var id = req.params.id;
    clientes[id] = req.body.cliente;
    res.redirect('/');
});

app.del('/cliente/:id', function(req, res){
    var id = req.params.id;
    delete clientes[id];
    res.redirect('/');
});

app.listen(3000);

Bom pessoal esse foi mais um episódio do mini-curso Node.js para leigos, espero que tenham gostado desse post, comentem abaixo, tire suas dúvidas, críticas e sugestões serão sempre bem-vindas também, até a próxima! :-D

12 respostas para Node.js para leigos – Framework Express Parte 2

  1. Sou iniciante e tive que quebrar um bocado da cabeça para poder corrigir um erro que surgiu aqui. (o erro era Error: Failed to lookup view “index”)

    Vou deixar uma sugestão, você poderia postar no tutorial como as pastas e os arquivos estão organizados nos diretorios do teu computador(Um printScreen seria o ideal). Porque pelo tutorial dá-se a impressão de que tudo está dentro da pasta View.

    O tutorial está ótimo, só fiquei bastante perdido na organização das pastas e diretorios.

    Parabéns pela iniciativa.

    • Obrigado pelos feedbacks, em breve irei atualizar os posts do Node.js para leigos, atualizando as versões das tecnologias utilizadas e explicando em detalhes com mais prints na tela. :D

  2. Primeiramente parabéns pelo ótimo material.
    Estou me aventurando um pouco com NodeJs+JqueryMobile e gostaria da sua ajuda para uma questão.
    No arquivo index.ejs tenho o caminho dos scripts.

    So que estes scripts não estão sendo localizados.
    Devo configurar algo no index.ejs? Estou utilizando views conforme exemplo acima.
    Obrigado.

      • Caio meus arquivos estão dispostos desta maneira.
        Pasta do projeto – D:\workspace\Musicas\assets\www
        Nela tenho os arquivos e pastas abaixo.
        Arquivo: server.js
        Pasta: jquery.mobile (arquivos js e css)
        Pasta: view (index.ejs)
        Dentro do arquivo index.ejs que carrego as configurações, da forma abaixo.

        Sei que estou vacilando em algum lugar. rs

  3. Pingback: Resumo da Semana Passada (12-18 Ago 2012) | Oscar Dias - Blog Pessoal

  4. The method “express.createServer();” is deprecated now is just “express();”.

      • Na versão 3.0 sim, é recomendado utilizar um var express pra isso pois há casos de configuração usando express e também com var app, por exemplo: app.configure(function(){ app.set(express.static()); });

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>