segunda-feira, 30 de dezembro de 2013

REST - Última Aula Prática - Resumo final

Vamos resumir essas doze aulas práticas que vimos e a partir do zero recriarmos todo nosso projeto (obviamente sem os fontes do CRUD, que como presente de Natal estão em um arquivo para ser baixado) através de 10 passos:

Passo 1: Instalar o Node.js.

Passo 2: Instalar o MongoDB.

Passo 3: Criar uma pasta para receber os dados do MongoDB (por exemplo C:\mongodb_data).

Passo 4: Levantar o MongoDB:
mongod --dbpath "C:\mongodb_data"
Passo 5: Instalar o Express:
npm install -g express@2.5.8
Passo 6: Criar a pasta do projeto (por exemplo app):
express app
Passo 7: Adicionar o Mongoose (biblioteca de conexão do banco) ao projeto no arquivo package.json na raiz do projeto:
...
  , "dependencies": {
      "express": "2.5.8"
    , "jade": ">= 0.0.1"
    , "mongoose": "2.6.5"
  }
}
Passo 8: Instalar o projeto, digitar o seguinte comando dentro da pasta app:
npm install
Passo 9: Baixar o arquivo com os fontes do projeto e descompactar substituindo os arquivos.

Passo 10: Na pasta app/server executar o servidor:
node server.js
Pronto já podemos ver nossa aplicação funcionando em qualquer navegador através do endereço http://localhost:3000/. Alguns detalhes bem impressionantes. Primeiro, toda a estrutura do banco de dados é criada automaticamente no momento do primeiro acesso. Segundo, é um sistema totalmente portátil, basta copiar essa pasta app completa para uma pendrive e executar novamente o servidor em qualquer máquina (desde que o MongoDB e o NodeJS estejam instalados - passos de 1 a 4).

Obrigado e até a próxima
Fernando Anselmo

domingo, 29 de dezembro de 2013

REST - Aula Prática - Excluir os Dados

Chegamos na última parte do nosso CRUD e para finalizarmos nosso projeto vamos eliminar os livros.

Mudar a Camada de Visão


Adicionamos mais um botão na tela da listagem dos dados. No arquivo index.html, na seção dos botões, inserimos a seguinte codificação:
   ...
    <div class="btn-group" ng-hide="nome == ''">
     <a class="btn btn-large" ng-click="excluir()">Excluir</a>
    </div>
   ...
Este botão será visível somente quando um livro for selecionado na listagem. Ao ser pressionado, chama a função excluir do arquivo controller.js. Adicionamos dentro da ListaCtrl (que controla a janela de listagem) uma função com a seguinte codificação:
function ListaCtrl($scope, $http) {
  ...
  $scope.excluir = function() {
    if ($scope.nome != '') {
      $http.delete('/excluir/' + $scope.nome)
        .success(function(data) {
          if (data == 'err') {
            alert("Houston, temos um problema");
          } else {
            alert("Livro Excluído...");
          }
          document.location.reload(true);
      })  
    }
  }  
}
Ao ser chamada, esta função executa o método delete da variável $http no qual é passado (como no processo da pesquisa da alteração) um caminho com o nome do livro selecionado. Verificamos a resposta se obteve ou não sucesso para eliminar o livro. O comando final reload é usado para reprocessar a página e fazer desaparecer da listagem o livro excluído.

Mudar a Camada de Dados


No arquivo funções do banco, adicionamos a função excluir (abaixo da função modificar):
exports.excluir = function (req, res) {
  livroModel.remove({nome: req.params.nom}).exec(function(err) {
    if (err) {
      callback(err);
    } else {
      res.send();
    }
  });
}
O comando remove do banco é usado para eliminar um registro com base nos parâmetros passados, funciona de mesma forma como o comando find já visto.

Mudar a Camada do Servidor


Adicionamos ao servidor a nova rota para exclusão:
app.delete('/excluir/:nom', routes.excluir);
E agora nos resta adicionar esse caminho no arquivo de rotas para disparar a função do banco, realizado através da seguinte codificação:
exports.excluir = function(req, res) {
  livro.excluir(req, res);
};
Pronto, observamos que a exclusão é o mais simples dos processos, assim, concluímos a letra D do nosso CRUD e com isso finalizamos nosso projeto. Espero que todas essas lições possam ser bem proveitosas para ajudar a divulgar a arquitetura REST.

Obrigado e até a próxima
Fernando Anselmo

quinta-feira, 26 de dezembro de 2013

REST - Aula Prática - Alterar os Dados (Parte 2)

Nesta segunda parte, iremos realizar a alteração dos dados a partir do formulário com o livro selecionado.

Mudar a Camada de Visão


Procedemos as seguintes adições no arquivo controller.js na função EditarCtrl:
function EditarCtrl ($scope, $http) {
  ... 

  $scope.modificar = function() {
    $http.put('/modificar/' + $scope._id, $scope.livro).success(function(data) {
      if (data == 'err'){
        alert("Houston, temos um problema");
      } else {
        alert("Livro Modificado...");
        window.location = '/';
      }
    })  
  }  
}
Esta função é chamada pelo botão Modificar do formulário que por sua vez passa o ObjectID e o livro modificado pelo formulário. Por que não passar o "nome"? Porque senão este campo não poderia ser alterado, a menos que optássemos por manter mais uma variável não editável contendo o nome não alterado. Após o livro ser alterado no banco retornamos (com o comando window.location) para a tela principal.

Mudar a Camada de Dados


Agora vamos proceder a modificação do livro no banco. No arquivo de funções, inserimos a seguinte função (abaixo da função procurar):
exports.modificar = function (req, res) {
  livroModel.update({_id: req.params.id},
    {nome: req.body.nome, autor: req.body.autor}).exec(function(err) {
    if (err) {
      callback(err);
    } else {
      res.send();
    }
  });
}
Com base no id passado, procedemos um comando update do banco. Este comando é dividido em duas partes, a primeira corresponde ao dado de localização e a segunda os campos a serem alterados. Se comparássemos com SQL a primeira parte seria o WHERE enquanto que a segunda os campos do SET.

Mudar a Camada do Servidor


No arquivo do servidor adicionamos a nova rota que recebe o parâmetro "id":
app.put('/modificar/:id', routes.modificar);
E terminamos com a adição do caminho para a chamada da tela no arquivo de rotas para chamar a função de banco criada:
exports.modificar = function(req, res) {
  livro.modificar(req, res);
};
Após o usuário alterar os dados na tela dispara a função modificar para a rota indicada passando a ObjectID e o livro como objeto encapsulado no corpo da requisição (request), exatamente por este motivo o método PUT é o mais indicado para alteração. Com essa concluímos a letra U e na próxima finalizaremos o nosso CRUD com a exclusão dos dados na tabela.

Obrigado e até a próxima
Fernando Anselmo

segunda-feira, 23 de dezembro de 2013

REST - Aula Prática - Alterar os Dados (Parte 1)

Optei por dividir a alteração por ser um tanto complexa (nada para morrer de susto). Nesta primeira parte, chamamos o formulário com o livro selecionado. Não pretendo me repetir deste modo, recomendo que veja a postagem anterior para tirar qualquer dúvida sobre qual arquivo modificar (que serão os mesmos e na mesma sequência).

Mudar a Camada de Visão


Adicionamos um botão na tela da listagem dos dados (abaixo do botão de Novo), na página que produz a listagem dos livros:
    ...
    <div class="btn-group" ng-hide="nome == ''">
     <a class="btn btn-large" href="/editar/{{nome}}">Editar</a>
    </div>
    ...
Este botão somente é visível ao selecionarmos um livro da listagem. Existe um evento ng-click="select(livro)" na tag "tr", que na Controller desta página, dispara a função select que atribui a variável $scope.nome a descrição do livro selecionado. Nosso próximo passo consiste em criar um formulário chamado quando o caminho editar for executado. Na pasta \views criamos a página editar.html com a seguinte codificação:
<!doctype html>
<html>
 <head>
  <meta Charest="UTF-8">
  <title>Teste AngularJS/NodeJS</title>
  <link rel="stylesheet" type="text/css" href="/css/bootstrap.css">
  <script src="/js/angular.min.js"></script>
  <script src="/js/controllers.js"></script>
 </head>
 <body ng-app ng-controller="EditarCtrl">
  <div class="container">
   <h2>Livro Selecionado</h2>
   <form ng-model="livro" name="livroform" class="form-horizontal">
    <div>
     <label for="nome" class="label" style="margin-right:6px;">Nome:</label>
     <input id="nome" placeholder="{{livro.nome}}" ng-model="livro.nome" />
    </div>
    <br />
    <div>
     <label for="autor" class="label" style="margin-right:6px;">Autor(es):</label>
     <input id="autor" placeholder="{{livro.autor}}" ng-model="livro.autor" />
    </div>
    <div class="form-actions">
     <button ng-click="modificar()" class="btn btn-primary">Modificar</button>
     <a href="/" class="btn">Voltar</a>
    </div>    
   </form> 
  </div>
 </body>
</html>
É quase uma cópia do formulário para a inserção do livro, alguns desenvolvedores optam por um único formulário e procedem as mudanças dinamicamente. Para não complicar demais, preferi deixá-los separados. Adicionamos a seguinte função no arquivo controller.js que responde a este formulário:
function EditarCtrl ($scope, $http) {
  $scope._id = 0;
  $scope.livro = {};
  var caminho = document.URL;
  caminho = caminho.substring(caminho.lastIndexOf('/'));
  $http.get('/lista/livro' + caminho).success(function(data) {
    $scope._id = data[0]._id;
    $scope.livro.nome = data[0].nome;
    $scope.livro.autor = data[0].autor;
  })
}
Da mesma forma que fizemos para listarmos vários livros, executamos uma função do banco que retorna (de modo Json) o registro selecionado.

Mudar a Camada de Dados


Necessitamos criar uma função para retornar um determinado livro. No arquivo de funções do banco, inserimos a seguinte função (abaixo da função gravar):
exports.procurar = function (req, res) {
  livroModel.find({nome: req.params.nom}).exec(function(err, livro) {
    if (err) { return console.log(err); }
    return res.json(livro);
  });
}
Não vamos brincar com ID's (que será utilizado somente no momento de proceder a alteração). Neste momento, poderíamos até passar a ObjectID, entretanto isso ficaria bem estranho no caminho URL (outras das pequenas regras de REST - Caminhos reconhecíveis pelo usuário), aqui trafegamos somente o que o usuário reconhece que é o nome. A função find localiza registros por qualquer parâmetro passado (é como um SELECT de SQL), vejamos alguns exemplos:

  • find({idade:{$gt:18}}) - Registros que possuem o campo idade maior que 18
  • find({valor:{$gt:50,$lt:100}}) - Registros que possuem o campo valor maior que 50 e menor que 100
  • find({editora :'OReilly'}).where('valor').gt(50).lt(100) - Registros que possuem o campo editora com o valor 'OReilly' e o campo valor maior que 50 e menor que 100
  • find({editora :'OReilly'}).limit(2)- Os dois primeiros registros que possuem o campo editora com o valor 'OReilly'
Acredito que já deu para sentir o que podemos produzir com a função "find".

Mudar a Camada do Servidor


No arquivo do servidor adicionamos duas novas rotas para chamar a tela e outra para disparar a função do banco criada, ambas recebem o parâmetro "nom":
app.get('/editar/:nom', routes.editar);
app.get('/lista/livro/:nom', livro.procurar);
E finalizamos com a adição do caminho para chamar a tela no arquivo de rotas:
exports.editar = function(req, res) {
  fs.readFile('../views/editar.html', function(error, content) {
    if (error) {
      res.writeHead(500);
      res.end();
    } else {
      res.writeHead(200, { 'Content-Type': 'text/html' });
      res.end(content, 'utf-8');
    }
  });
};
O que acontece? O usuário seleciona um determinado registro da listagem e em seguida pressiona o botão Editar, este dispara a rota "/editar/nome" que chama o formulário. Através da "Controller" uma nova rota é disparada a "/lista/livro/nome" que executa a função procurar e fornece uma página Json com o registro selecionado, este é carregado para a variável $scope.livro e mostrado na página. Na próxima continuamos nosso CRUD com a segunda parte da modificação dos dados na tabela.

Obrigado e até a próxima
Fernando Anselmo

sábado, 21 de dezembro de 2013

REST - Aula Prática - Inserir os Dados

Antes de começarmos é muito importante que veja a postagem anterior sobre a nova organização do projeto. Existem várias maneiras de realizarmos um CRUD, optei pela mais simples, a listagem dos dados e três botões o primeiro chama a tela para inclusão de registros, o segundo chama a tela para a modificação de um registro selecionado na listagem e o último elimina o registro selecionado na listagem.

Mudar a Camada de Visão


Dessa vez vamos mudar da visão ao servidor, nosso primeiro passo consiste em adicionar um botão na tela da listagem dos dados, para isso no arquivo \views\index.html adicionamos a seguinte codificação:
   ...
   <h2>Meus Livros</h2>
   <div class="btn-toolbar">
    <div class="btn-group">
     <a class="btn btn-large" href="/novo">Novo</a>
    </div>
   </div>

   <label for="criteria" class="label" style="margin-right:6px;">Pesquisar</label>
   ...
Devemos observar o local onde este botão será inserido. Nosso próximo passo consiste em adicionar o formulário a ser chamado quando este botão for pressionado. Na pasta \views criamos uma página chamada novo.html com a seguinte codificação:
<!doctype html>
<html>
 <head>
  <meta Charest="UTF-8">
  <title>Teste AngularJS/NodeJS</title>
  <link rel="stylesheet" type="text/css" href="/css/bootstrap.css">
  <script src="/lib/angular.min.js"></script>
  <script src="/javascript/controllers.js"></script>
 </head>
 <body ng-app ng-controller="NovoCtrl">
  <div class="container">
   <h2>Novo Livro</h2>
   <form ng-model="livro" name="livroform" class="form-horizontal">
    <div>
     <label for="nome" class="label" style="margin-right:6px;">Nome:</label>
     <input id="nome" ng-model="livro.nome" size="80" />
    </div>
    <br />
    <div>
     <label for="autor" class="label" style="margin-right:6px;">Autor(es):</label>
     <input id="autor" ng-model="livro.autor" />
    </div> 
    <div class="form-actions">
     <button ng-click="criar()" class="btn btn-primary">Salvar</button>
     <a href="/" class="btn">Voltar</a>
    </div>    
   </form> 
  </div>
 </body>
</html>
Temos então um formulário para fornecer os dados a um objeto de Livro. Devemos lembrar que a arquitetura REST prega a utilização dos seguintes métodos:
  • POST para o evento de inclusão dos dados;
  • PUT para o evento de alteração dos dados; e 
  • DELETE para o evento de exclusão dos dados.
Respeitaremos essas indicações, no arquivo \sist\javascript\controllers.js adicionamos a função NovoCtrl (abaixo da função ListaCtrl) que gerencia esta página:
function NovoCtrl ($scope, $http) {
  $scope.criar = function() {
    $http.post('/criar', $scope.livro)
      .success(function(data){
        if (data == 'err'){
          alert("Houston, temos um problema");
        } else {
          alert("Livro Incluído...");
        }
        $scope.livro={};
    })  
  }  
}
Criamos uma função de escopo chamada criar que é utilizada pela tela (na Controller tudo o que é de $scope pode ser compartilhado com a tela), e ao ser chamada executa o método post da variável $http com a passagem do caminho e um objeto de Livro. Verifica a resposta se obteve ou não sucesso para inserir o novo livro.

Mudar a Camada de Dados


No arquivo \views\dados\livroFuncoes.js adicionamos a função gravar (abaixo da função listar):
exports.gravar = function (req, res) {
  var novoLivro = new livroModel({
    nome:req.body.nome,
    autor:req.body.autor
  });
  novoLivro.save(function (err) {
    if (err) {
      callback(err);
    } else {
      res.send();
    }
  });
}
Através do corpo da requisição (variável req) temos os dados do formulário. Certa vez me perguntaram se não era necessário gravar um id, perguntei se desejava trabalhar totalmente Orientado a Objetos ou não, não existem ids em OO (isso é coisa de banco relacional que precisa de chaves primárias para localizar registros), o que existe é o ObjectID que é mantido e controlado pelo banco, e com esse só vou me importar ao alterar um registro. Para adicionarmos um novo (repare o comando new) objeto no banco, disparamos o método save que envia se a informação foi ou não incluída no Banco.

Mudar a Camada do Servidor


Precisamos de mais duas pequenas alterações, no arquivo \server\server.js adicionamos as novas rotas (na seção "Rotas do Sistema"), uma para chamar a tela e outra para disparar a função do banco:
app.get('/novo', routes.novo);
app.post('/criar', routes.criar);
E por fim adicionamos esses caminhos no arquivo \routes\index.js através da seguinte codificação:
exports.novo = function(req, res){
  fs.readFile('../views/novo.html', function(error, content) {
    if (error) {
      res.writeHead(500);
      res.end();
    } else {
      res.writeHead(200, { 'Content-Type': 'text/html' });
      res.end(content, 'utf-8');
    }
  });
};

exports.criar = function(req, res) {
  livro.gravar(req, res);
};
Já podemos inserir os registros em nosso banco (ou seja, concluímos a letra C), na próxima continuamos o nosso CRUD com a primeira parte da modificação dos dados na tabela.

Obrigado e até a próxima
Fernando Anselmo

segunda-feira, 16 de dezembro de 2013

REST - Aula Prática - Arrumar o Projeto e Listar os Dados

Na postagem anterior vimos como colocar os dados no MongoDB, só que ao rever os arquivos anteriores descobri que deixei algumas coisas um tanto mal organizadas (o que pode prejudicar lá na frente) então permita-me nesta postagem arrumar o projeto para finalizarmos nosso CRUD.

Qual editor utilizar?


Essa é uma dúvida que muitas pessoas me fazem. Qualquer um serve entre o NotePad++ ao Eclipse, prefiro usar um editor intermediário, como o Free JavaScript Editor que possui inclusive autocomplete de código. O mais famoso deles se chama Sublime Text, muitos professores que usam Mac o utilizam, existem versões para Windows e Linux também, só que o preço da licença (70 dólares) chega a assustar muitas pessoas.

Arrumar a Camada do Servidor


Trocamos o nome do arquivo do servidor para server.js e o colocamos na pasta \server, com a seguinte codificação:
if (!process.env.NODE_ENV) process.env.NODE_ENV='development'

var express = require('express'),
  routes = require('../routes'),
  livro = require('../dados/livroFuncoes.js');

var app = module.exports = express.createServer();

app.configure(function(){
  app.use(express.bodyParser());
  app.use(express.methodOverride());
  app.use(app.router);
  app.use('/css', express.static(__dirname + './../public/stylesheets'));
  app.use('/js', express.static(__dirname + './../public/javascripts'));
});

// Ambientes
app.configure('development', function(){
  app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});
app.configure('production', function(){
  app.use(express.errorHandler());
});

// Rotas do Sistema
app.get('/', routes.index);
app.get('/lista/livro', livro.listar);

// Ativar o Servidor
app.listen(3000);
console.log("Servidor está executando na porta %d em modo de %s", app.address().port, app.settings.env);
Na primeira linha, definimos o modo que o servidor é iniciado em development (desenvolvimento) ou production (produção), veja na seção ambientes as diferenças (aqui basicamente se mostrará ou não uma trilha de erro completa). Em seguida vemos as bibliotecas de uso e a configuração do servidor. O caminho das rotas de acesso e o inicio do servidor na porta 3000.

Para completar a definição desses caminhos, na pasta \routes existe por padrão um arquivo chamado index.js, devemos deixá-lo com a seguinte codificação:
var fs = require('fs'); 
 
exports.index = function(req, res){
  fs.readFile('../views/index.html', function(error, content) {
    if (error) {
      res.writeHead(500);
      res.end();
    } else {
      res.writeHead(200, { 'Content-Type': 'text/html' });
      res.end(content, 'utf-8');
    }
  });
};
Este arquivo contém os caminhos (as rotas) do sistema, e indica qual arquivo é chamado, no servidor deixamos apenas as indicação dos caminhos para este arquivo.

Arrumar a Camada de Dados


Agora vamos organizar os arquivos que fazem a comunicação com o banco MongoDB. Na pasta principal \app criamos uma pasta chamada \dados e adicionamos o arquivo livroFuncoes.js com a seguinte codificação:
banco = require('./livroDb.js'),
exports.listar = function (req, res){
  livroModel.find().exec(function(err, livro) {
    if (err) { return console.log(err); }
    return res.json(livro);
  });
} 
Este arquivo é responsável por todas as funções de acesso a tabela (em breve teremos a inclusão, alteração, exclusão), neste momento, possui uma única função que retorna uma listagem dos dados do arquivo em formato Json. Criamos, também nesta pasta, um arquivo chamado livroDb.js com a seguinte codificação:
mongoose = require('mongoose');

// Conexão com o Banco 
mongoose.connect('mongodb://localhost:27017/livro');
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function calbckcallback() {
    init();
});

function init() {
    schema = new mongoose.Schema({
      nome: {type: String, unique: true},
      autor: String
    });
    livroModel = mongoose.model('Livro', schema);
}
Este era o nosso antigo arquivo db.js. Aqui temos uma conexão com o banco e a função init() que determina como é a estrutura da tabela.

Arrumar a Camada de Visão


Copiamos todo o conteúdo da pasta \sist para a pasta \views. Nesta pasta \views:
  • Copiamos o arquivo \css\bootstrap.css para a pasta \public\stylesheets e eliminamos a pasta \css.
  • Copiamos os arquivos \javascript\controllers.js, \lib\angular.min.js e \lib\angular.min.js.map para a pasta \public\javascripts e eliminamos as pastas \javascript e \lib.

Na pasta \views criamos o arquivo index.html com a seguinte codificação:
<!doctype html>
<html>
 <head>
  <meta Charest="UTF-8">
  <title>Teste AngularJS/NodeJS</title>
  <link rel="stylesheet" type="text/css" href="/css/bootstrap.css">
  <script src="/js/angular.min.js"></script>
  <script src="/js/controllers.js"></script>
 </head>
 <body ng-app ng-controller="ListaCtrl">
  <div class="container">
   <h2>Meus Livros</h2>
   <label for="criteria" class="label" style="margin-right:6px;">Pesquisar</label>
   <input id="criteria" type="search" ng-model="criteria">
   <table class="table table-striped table-hover table-bordered">
    <thead>
     <th>Título</th>
     <th>Autor(es)</th>
    </thead>
    <tr ng-repeat="livro in livros | filter:criteria | orderBy:'nome'"
        ng-click="select(livro)" ng-class="{'info': nome == livro.nome}">
     <td>{{livro.nome}}</td>
     <td>{{livro.autor | uppercase}}</td>
    </tr>
   </table>
  </div>
 </body>
</html>
Mostramos uma listagem principal dos dados conforme vimos anteriormente no arquivo hello.html. Preferi republicá-lo neste outro arquivo para completarmos nossa padronização da codificação e não restar mais nenhuma dúvida. O próximo arquivo fica na pasta \views\javascript, é o arquivo controllers.js e possui a seguinte codificação:
function ListaCtrl($scope, $http) {
  $scope.nome = '';
  $http.get('/lista/livro').success(function(data) {
    $scope.livros = data;
  })
  $scope.select = function(livro) {
    $scope.nome = livro.nome;
  }
}
Esta função acessa o Json e obtém os dados para carregar a variável $scope.livros para o preenchimento da tabela. A função select será utilizada quando na seleção de um registro (para as funções de alteração e exclusão).

Nossa estrutura final ficou com o seguinte formato:
/app - Pasta raiz do projeto
 /dados - Camada de Dados
  livroDB.js - Acesso ao MongoDB
  livroFuncoes.js - Funções da tabela "livros"
 /public
  /images - imagens do projeto
  /javascripts - bibliotecas e controllers
   angular.min.js - Biblioteca do AngularJS
   angular.min.js.map - Mapeamento do AngularJS
   controllers - Arquivo de Controller para o AngularJS
  /stylesheets
   bootstrap.css - Arquivo de estilos do Bootstrap
   style.css - Arquivo de estilos criado por padrão
 /routes
  index.js - Contém as rotas do sistema
 /server - Camada do Servidor 
  server.js - Inicia o servidor (na linha de comando: supervisor server.js)
 /views - Camada de Visão
  index.html - Janela principal do sistema
A única pasta que está faltando é a \node_modules que são os módulos utilizados como: express, mongoose e supervisor. Essa organização foi necessária para podermos continuar com nossos estudos.

Com esta implementação podemos ver os dados que foram inseridos no banco (ou seja, concluímos a letra R), na próxima postagem continuaremos nosso CRUD com a inserção dos dados na tabela.

Obrigado e até a próxima
Fernando Anselmo

segunda-feira, 9 de dezembro de 2013

REST - Aula Prática - Brincar com o MongoDB

Nosso projeto atualmente se encontra com a seguinte configuração, já temos o AngularJS, Bootstrap e Node.js, esse último sendo comandado pelo Supervisor, além disso sua funcionalidade é uma única tela capaz de listar os dados que estão no servidor (app.js). O problema é que na camada de Dados temos o "fake" de uma lista que não armazena nada.

Já falei sobre o MongoDB e agora vamos nos aprofundar muito mais nesse banco e seu relacionamento com o Node.js. Já publiquei uma postagem sobre esses dois juntos e recomendo fortemente que leia-o antes de se aventurar aqui pois odeio ser repetitivo.

Tipos Suportados

Um detalhe super interessante no uso do MongoDB com Javascript é a quantidade de tipos nativos que são suportados ou convertidos, vamos a eles:

  • Float é de 8 bytes e diretamente conversível para o tipo Number do Javascript
  • Double Class para uma classe representando um valor float, útil quando se utiliza coleções onde é necessário a garantia que os valores são sempre em ponto flutuante.
  • Integer32 e Integer64 é um pouco mais complicado, pelo fato que o Javascript representa todo número acima dos 64 bits como float, resultado que o máximo valor do inteiro está em 53 bits. O MongoDB possui dois tipos de inteiros, de 32 bits e 64 bits. Resultado que o driver (Mongoose) vai encaixar bem o valor de 32 bits, e se tiver que promovê-lo para 64 bits enquadrá-lo em 53 bits, se puder. Se não for possível retornará uma instância da Long class para evitar a perda de precessão.
  • Long class permite armazenar os inteiros de 64 bits.
  • Três tipos que possuem um mapeamento direto para JavaScript:
    • Date trabalho com datas.
    • RegExp trabalho com expressões regulares
    • String tipo caractere (codificada em UTF-8)
  • Binary Class armazenagem dados grandes.
  • Code Class funções javascript, pode fornecer um escopo para executar esse método.
  • ObjectID Class contém um identificador de documento MongoDB (o equivalente a uma chave primária)
  • DBRef Class inclusão de uma referência em um documento apontando para um outro objeto
  • Symbol Class especificar um símbolo, não é realmente relevante para Javascript, mas para idiomas que suporta o conceito de símbolos.

Adicionar os Dados do MongoDB

Siga a postagem anterior para configurar o projeto com o MongoDB (adicionar o Mongoose ao projeto e o arquivo db.js para realizar a conexão). Com isso pronto inicie e acesse o console do MongoDB e digite os seguintes comandos (pressione Enter ao final de cada uma das linha):
use livro
db.livros.save({nome:'Effective Java', autor:'Joshua Bloch'})
db.livros.save({nome:'Year without Pants', autor:'Scott Berkun'})
db.livros.save({nome:'Confessions of public speaker', autor:'Scott Berkun'})
db.livros.save({nome:'JavaScript Good Parts', autor:'Douglas Crockford'})
db.livros.save({nome:'AngularJS', autor:'Brad Green & Shyam Seshadri'})
db.livros.save({nome:'Node.js in Action', autor:'Mike Cantelon, TJ Holowaychuk & Nathan Rajlich'})
db.livros.save({nome:'Node: Up and Running', autor:'Tom Hughes-Croucher & Mike Wilson'})
Pronto, nesse momento temos a nossa base de livros e autores no MongoDB, próximo passo é fazê-la aparecer na tela. Como sei que deseja tentar realizar isso primeiro deixarei como exercício para nosso próximo encontro.

Obrigado e até a próxima
Fernando Anselmo