sábado, 23 de novembro de 2013

REST - Aula Prática - AngularJS e NodeJS com Supervisão

Começamos nossa aplicação, porém quero entender alguns detalhes: Primeiro, por quê estamos usando o "Bootstrap" se quase não estamos utilizando um layout decente? Segundo, toda vez que mudamos algo no servidor teremos que derrubá-lo e iniciá-lo novamente? E terceiro, cadê a vantagem em usar o "AngularJS"? Do jeito que está acho que um simples HTML resolve. Armei algumas perguntas e nesta postagem pretendo corrigí-las.

Usando Realmente o Bootstrap e o AngularJS

Antes de mais nada quero confessar que sou um leitor compulsivo, então vamos mudar um pouco o escopo dessa aplicação de "discos" para "livros". Alteramos a variável ficheInfo no arquivo app.js para a seguinte variável:

var fichaLivro=[
  {nome:'Effective Java', autor:'Joshua Bloch'},
  {nome:'Year without Pants', autor:'Scott Berkun'},
  {nome:'Confessions of public speaker', autor:'Scott Berkun'},
  {nome:'JavaScript Good Parts', autor:'Douglas Crockford'},
  {nome:'AngularJS', autor:'Brad Green & Shyam Seshadri'},
  {nome:'Node.js in Action', autor:'Mike Cantelon, TJ Holowaychuk & Nathan Rajlich'},
  {nome:'Node: Up and Running', autor:'Tom Hughes-Croucher & Mike Wilson'}
]
...
app.get('/api/ficha', function(req, res) {
  res.json(fichaLivro);
});

Devemos pensar que em breve esses dados virão do MongoDB (em um próximo artigo). Vamos manter essa tabela relativamente simples, com o nome do livro e seus respectivos autores, apenas para não termos que nos preocupar em aprender comandos complexos do banco (o objetivo é aprender Arquitetura REST). Modificamos o arquivo hello.js de forma a armazenar os dados da página JSON gerada em uma variável:

function lstControl($scope,$http){
  $http.get('/api/ficha').success(function(data){
    $scope.livros = data;
  })
  $scope.index = -1;
  $scope.select = function(index) {
    $scope.index = index;
    $livro = $scope.livros[index];
  }
}

Um novo método select armazena um livro selecionado na tabela para fins de modificação. Por fim, trabalhamos sobre o HTML, iremos utilizar às praticidades do Bootstrap e do AngularJS como se deve, modificamos o arquivo hello.html para:

<!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/hello.js"></script>
 </head>
 <body ng-app ng-controller="lstControl">
  <div class="container">
   <h2>Meus Livros</h2>
   <div class="btn-toolbar">
    <div class="brn-group">
     <a class="btn btn-large" href="">Editar</a>
    </div>
   </div> 
   <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($index)" ng-class="{'info': $index == index}">
     <td>{{livro.nome}}</td>
     <td>{{livro.autor | uppercase}}</td>
    </tr>
   </table>
  </div>
 </body>
</html>

Toda a especificação CSS3 virá do Bootstrap, logo no começo temos um DIV que pertence a classe "container" que é a principal, então todos os outros elementos seguirão esta informação. Ganhamos uma barra de botões (futuramente será utilizada para I-A-E). Nossa tabela recebeu mais um item no qual podemos filtrar os livros (seja pelo título ou autor), isso acontece graças a um filtro (filter) do elemento ng-repeat. A tabela também está ordenada (orderBy) pelo campo 'nome'. Todos esses novos detalhes são realizados dinamicamente através do Ajax. Outra brincadeira foi quanto ao nome dos autores, que agora aparece sempre em letras maiúsculas (observe o 'uppercase'). Podemos selecionar cada elemento da tabela (futuramente para editar/excluir) que será destacado dos outros (através da ng-class), para realizar isso, capturamos o ng-click que é enviado para o método select que guarda este registro.

Supervisor

O que se entende por "hot-deploy"? É a capacidade de um servidor detectar se ocorreram mudanças em seus arquivos e disponibilizar para o cliente uma nova versão da aplicação. Supervisor é um pequeno script para o Node.js, simplesmente fica "escutando" as mudanças no código, e em caso positivo realiza um "hot-deploy", porém sem se preocupar com vazamentos de memória ou se certificar de limpar todas as referências inter-módulo, ou seja, excelente para um ambiente de desenvolvimento mas terrível para um de produção. Podemos proceder sua instalação pelo NPM da seguinte forma:

npm install supervisor -g

E agora iniciamos o servidor com:

supervisor app.js

Qualquer alteração em qualquer arquivo, será automaticamente detectada e servidor será reiniciado. Como dever de casa para a próxima lição, tente fazer com que ao clicar no botão editar seja chamado um formulário contendo o livro.

Obrigado e até a próxima
Fernando Anselmo

sexta-feira, 15 de novembro de 2013

REST - Aula Prática - AngularJS e NodeJS

Até o presente momento aprendemos como utilizar um monte de softwares de modo independente e agora começamos a juntar todas às ideias. Porém, gostaria de lembrar que REST é uma Arquitetura e que pode ser aplicada a qualquer software, escolhi JavaScript simplesmente para mostrar que é possível criar um sistema interessante com essa tecnologia.

Considere as postagens passadas como pré-requisitos obrigatórios.

Montando o Ambiente

Inicialmente precisamos baixar o AngularJS, para isso digite:
bower install angular

Veja mais referências sobre o Bower na postagem anterior. Para montarmos a estrutura do nosso sistema digite

express app
cd app
npm install

Crie dentro da pasta "app" a seguinte estrutura de pastas:

/sist
   /css
   /javascript
   /lib

Copie os seguintes arquivos:

  • Para a pasta "css" copie o arquivo "bower_components\bootstrap\docs\assets\css\bootstrap.css"
  • Para a pasta "lib" copie o arquivo "bower_components\angular\angular.min.js"

Pronto, toda a estrutura do nosso projeto já está montada.

AngularJS através do Servidor NodeJS

Começamos nossa aplicação na pasta "app", modifique o arquivo app.js:

var ficheInfo=[
  { id:1, nom:"Paulinho", prenom:"Moska" },
  { id:2, nom:"Maria", prenom:"Gadú" },
  { id:3, nom:"Cássia", prenom:"Eller" }
]

var express = require('express'),
  routes = require('./routes'),
  fs = require('fs');

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

app.configure(function(){
  app.set('views', __dirname + '/views');
  app.set('view engine', 'jade');
  app.use(express.bodyParser());
  app.use(express.methodOverride());
  app.use(app.router);
  app.use(express.static(__dirname + '/public'));
  app.use('/javascript', express.static(__dirname + '/sist/javascript'));
  app.use('/lib', express.static(__dirname + '/sist/lib'));
});

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('/', function(req, res) {
  fs.readFile('./sist/hello.html', function(error, content) {
    if (error) {
      res.writeHead(500);
      res.end();
    } else {
      res.writeHead(200, { 'Content-Type': 'text/html' });
      res.end(content, 'utf-8');
    }
  });
});
app.get('/api/affiche', function(req, res) {
 res.json(ficheInfo);
});

app.listen(3000);
console.log("Express server listening on port %d in %s mode", app.address().port, app.settings.env);

Lembramos que este arquivo é o "tiro inicial" do nosso servidor. As modificações neste arquivo foram:

  • A criação de uma lista de artistas com a seguinte estrutura: id, nome e sobrenome.
  • A adição da FS para lermos arquivos.
  • A disponibilização de uso das duas pastas contidas na pasta "sist"
  • A modificação da rota padrão "/" para a execução do arquivo "hello.html".
  • A adição da rota "/api/affiche" que gera uma saída em formato JSON da nossa lista de artistas criada inicialmente.

Uma das características de um sistema REST é a pré-descrição da arquitetura de GET e POST, ou seja, todas as rotas devem existir como identificação no servidor. Na pasta "sist" crie um arquivo chamado "hello.html" e adicione as seguintes linhas:

<!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/hello.js"></script>
 </head>
 <body ng-app ng-controller="monControl">
  <h3>Listagem dos Cantores</h3>
  <div ng-repeat="a in artistas">
   <p>{{a.id}}. {{a.nom}} {{a.prenom}}</p>
  </div>
 </body>
</html>

Como visto na aula de Listas com o AngularJS, temos a tag "ng-repeat" que interage com coleções. Na pasta "javascript" crie um arquivo chamado "hello.js" e adicione as seguintes linhas:

function monControl($scope,$http){
 $http.get('/api/affiche').success(function(data){
  $scope.artistas = data;
 })
}

No controller "monControl" carregado para a variável de escopo "list o resultado da chamada da pasta "/api/affiche" que será produzida via JSON através do NodeJS. É dessa forma que ocorre a interação entre o NodeJS e o AngularJS, o servidor produz um conteúdo e o cliente obtém através de uma URL. Agora resta apenas executar a aplicação com o comando:

node app.js

Acesse o endereço: http://localhost:3000/, e veja a aplicação funcionando.

Obrigado e até a próxima
Fernando Anselmo