Conhecendo a stack MEAN: MongoDB, Express, Angular e Node.

Nos últimos anos, talvez por culpa da revolução Ajax, o JavaScript deixou de ser uma toy language e ganhou muita força. Foi nessa expansão dos horizontes da linguagem que surgiu o Node, um ambiente de execução JavaScript baseado na engine V8 da Google. Agora temos JavaScript também no lado do servidor! Node.js segue o paradigma de programação orientada a eventos e non-blocking I/O, resultando em ótima performance para determinados cenários de aplicações real-time.
Além do Node, um outro framework que vem ganhando tração é o AngularJS, da Google.

Em meio a essa expansão do JavaScript na web, foi criado o MEAN stack:

  • MongoDB – Banco de dados orientado a documentos
  • Express – Framework de desenvolvimento web para Node
  • AngularJS – Framework MVC para JavaScript
  • Node.js – Ambiente de execução JavaScript

nodejs-1024x768

Mas por que usar essa seleção de ferramentas?

De início, temos a vantagem de não precisar saber nenhuma linguagem além do JavaScript. O que também é uma grande vantagem quando queremos utilizar um banco de dados NoSql, como o MongoDB, já que estaremos trabalhando direto com objetos muito similares ao JSON. Essas características tornam o MEAN Stack ideal para rápida prototipação de software e desenvolvimento de aplicações escaláveis. Por ser usado apenas uma linguagem bem difundida, como o JavaScript, é adequado também para desenvolvedores que não tem muita experiência com o desenvolvimento backend.

Por onde começar?

Com o MongoDB, Node, npm (node package manager) e Express instalados, vamos criar um novo projeto usando o Express e instalando os módulos mongodb e mongoose.
Usaremos o mongoose para trabalhar de forma simplificada com MongoDB.
No exemplo abaixo, usaremos o template engine “ejs”

express -e cadastro-de-contatos

Dentro do diretório cadastro-de-contatos, altere as dependências no arquivo package.json da seguinte maneira:

"dependencies": {
  "express": "3.4.3",
  "ejs": "*",
  "mongodb": "~1.3.19",
  "mongoose": "~3.8.1"
}

Agora, rode o comando npm install para baixar os módulos necessários

Primeiro, vamos iniciar o AngularJS:

<html ng-app>

Agora, podemos criar o formulário para adicionar novos contato, no arquivo views/index.ejs, que invocará a função adicionaContato.

<section ng-controller='ContatosController'>
  <form ng-submit='adicionaContato()'>
  <input type='text' placeholder='nome' ng-model='contato.nome' />
  <input type='tel' placeholder='telefone' ng-model='contato.telefone' />
  <input type='submit' value='salvar' />
  </form>
</section>

Repare que definimos que os campos de input estão vinculados a um objeto no controller, e o formulário chamará a função adicionaContato quando o submetermos. Vamos criar o ContatosController.js:

function ContatosController($scope, $http) {

  function Contato() {
    this.nome = '';
    this.telefone = '';
  }

  $scope.contato = new Contato();

  $scope.contatos = [];

  $scope.adicionaContato = function() {
    $http.post('/contato', $scope.contato).success(function() {
      $scope.contatos.push($scope.contato);
      $scope.contato = new Contato();
    });
  }
}

A função adicionaContato faz um post assíncrono para /contato, enviando o objeto contato no corpo da requisição.
Mas essa rota ainda não existe! Ainda temos que defini-la no servidor, no  arquivo app.js:

app.post('/contato', routes.adicionaContato);

Quando a requisição for feita, o contato será persistido no banco, mas ainda temos que criar a estrutura dos documentos de contato que serão gravados. Faremos isso utilizando o mongoose em nosso routes/index.js:

var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/mean');
var Schema = mongoose.Schema;

var contatoSchema = new Schema({
  nome: { type: String, required: true },
  telefone: { type: String, required: true }
});

Ainda no routes/index.js, devemos criar a função que será chamada quando o post para /contato for feito:

exports.adicionaContato = function(req, res) {
  var contato = new Contato(req.body);
  contato.save(function(error, contato) {
    if(error) res.send(500);

    res.send(201);
  });
}

Pronto. Já estamos persistindo o contato no banco. Podemos testar nossa aplicação rodando o comando node app.js e abrindo a acessando a url http://localhost:3000/. Repare que não mapeamos o contato em momento algum, e todo o código escrito, tanto no cliente quanto no servidor, foi JavaScript.

Podemos agora fazer a listagem dos contatos. No views/index.ejs:

<table class="table table-striped">
  <tr>
    <th>Nome</th>
    <th>Telefone</th>
  </tr>
  <tr ng-repeat='contato in contatos'>
    <td>{{contato.nome}}</td>
    <td>{{contato.telefone}}</td>
  </tr>
</table>

Vamos também fazer a busca dos contatos no controller do Angular ContatosController.js:

function ContatosController($scope, $http) {

  // Resto do código

  $http.get('/contatos').success(function(retorno) {
    $scope.contatos = retorno.contatos;
  });
}

Estamos fazendo um get assíncrono para /contatos. Da mesma forma que fizemos com o post, temos que definir a rota no servidor, no arquivo app.js:

app.get('/contatos', routes.listaContatos);

E no routes/index.js, faremos a busca no banco:

exports.listaContatos = function(req, res) {
 Contato.find({}, function(error, contatos) {
 if(error) res.send(500);

res.json({ contatos: contatos });
 });
}

Pronto! É JavaScript em todos os lados, que pode até confundi-lo, no início, de onde vai cada código!

Todo o código do artigo pode ser encontrado neste repositório.

16 Comentários

  1. Joao 10/12/2013 at 10:17 #

    A partir do “A função adicionaContato faz um post assíncrono para /contato, enviando o objeto contato no corpo da requisição.” não entendi mais nada.

  2. Caio Ribeiro Pereira 10/12/2013 at 14:49 #

    Show! Também recomendo um novo framework Node.js, 100% full-stack, o Meteor

  3. Caio Ribeiro Pereira 10/12/2013 at 14:51 #

    Pra quem quiser aprender como brincar com Node.js veja no link abaixo, um roteiro legal de posts para ler:
    http://udgwebdev.com/nodejs

  4. Christian Reichel 11/12/2013 at 09:11 #

    Muito bom.
    O ecosistema js esta ficando bem legal.

    Algumas ferramentas que nao foram citadas:

    – npm: package manager do node, para os javeiros ele lembr a um pouco o maven, para os linuxers o apt-get|yum

    – bower: gerencia as depende3ncias de js no lado do client

    – Yeoman: scaffolding tool. Gera um projeto para voce (maven archetypes)

    – grunt: faz o build, executa o server e roda os testes (maven, gradle)

    (desculpe pela falta de acentos)

  5. Flávio Almeida 11/12/2013 at 13:23 #

    Olá Christian, aqui no blog da Caelem já existem posts sobre grunt, yeonam e bower. Você pode conferir nos links abaixo:

    http://blog.caelum.com.br/experimente-o-yeoman-em-seu-workflow-de-projetos-front-end/

    http://blog.caelum.com.br/automacao-de-build-de-front-end-com-grunt-js/

  6. Márcio 17/12/2013 at 14:41 #

    O novo http://www.walmart.com.br usa node.js, dust template linkedin, express e muitas outras coisinhas…

  7. Suissa 17/12/2013 at 18:19 #

    MEAN eh o que há de melhor \o/

  8. Luiz Augusto 13/02/2014 at 14:55 #

    Eu proponho uma nova sigla para desenvolvimento para desktop utilizando tecnologia WEB.

    Estou usando um projeto e o resultado foi um sucesso.

    Eu chamo de MEANT

    MongoDB – Banco de dados orientado a documentos
    Express – Framework de desenvolvimento web para Node
    AngularJS – Framework MVC para JavaScript
    Node.js – Ambiente de execução JavaScript
    Topcube – webkit que trabalha junto com o node

  9. Marcelo 30/07/2014 at 17:48 #

    Tem também o B-MEAN…o B seria de Breeze, e ajuda a fazer toda essa questão WEB com javascript ter mais segurança quando acessado em ambientes corporativos. Tipo, acessar ERP’s, e outras questões.

  10. Sylvio 05/01/2015 at 16:37 #

    Opa, blz?

    Então, seguir todo o processo acima, mas na hora de executar o app no http://localhost:3000/ ele dah esse erro: http://nsae02.casimages.net/img/2015/01/05/150105073638558238.png

    PS: Testei com o seu App e deu no mesmo erro..

  11. David 02/12/2015 at 17:45 #

    Ola Vitor. Testei esta aplicação acessando via pc e via mobile. Porém notei que a tal reatividade do Node não aconteceu. Falta alguma configuração, pacote npm? Abraço e parabéns pelo tutorial.

  12. Rogério Sousa 13/05/2016 at 15:03 #

    Então visto sua dinâmica de desenvolvimento agil , ficou uma duvida quanto a isso , ruby on rails ou mean stack, qual o melhor para aplicações de grande porte?

  13. wellington da silva leite 15/05/2016 at 15:48 #

    adorei o novo Framework vamos desenvolver novos projetos voltados a este campo.

    sunga boxer
    http://www.grigocollection.com.br/sunga-boxer

  14. Eric Silva 25/08/2016 at 15:33 #

    Boa tarde pessoal da Caelum,

    Teria como dar uma contextualizada neste post? Estou tentando implementar esse tutorial e até mesmo rodar o código pronto de vocês que esta no git. E simplesmente, não dá certo.
    Esta dando um erro MODULE_NOT_FOUND para o módulo bson.

    Desde já obrigado.

  15. Ronaldo Oshikawa 05/09/2016 at 11:23 #

    Bom dia,

    Estou com uma oportunidade para um Mean Stack para região de Franca – SP.
    Link Linked In: http://goo.gl/dtxjUv

    Experiência nas etapas de análise conceitual e desenvolvimento de aplicações de negócio utilizando JavaScript e Node.Js para back-end;
    Sólidos conhecimentos no desenvolvimento de API Gateway e utilização de LoopBack, Express, Bluebird e Gulp;
    Utilização de repositórios Git.

    Projeto período indeterminado. Local de trabalho: Franca – SP
    Interessados enviar CV para r.oshikawa@avance-authent.com.br

    Agradeço as indicações.

Deixe uma resposta