SlideShare uma empresa Scribd logo
1 de 196
Baixar para ler offline
Victor Hazin
victor@hazin.com.br
Victor Hazin
Engenheiro de Software do CESAR (+ 7 anos)
Professor da FBV Devry (+3 anos)
Graduação e Mestrado em Ciências da
Computação (CIn-UFPE) (2010 e 1013)
https://goo.gl/M17B7J
Presentation layer Business Logic layer Data Access layer
Full Stack Web Development
Presentation layer Business Logic layer Data Access layer
Front-end Back-end
Presentation layer Business Logic layer Data Access layer
NodeJS
and
NodeJS Modules
Single page Apps
using Javascript Frameworks
(AngularJS)
MongoDB
JSON documents
REST API

serving JSON
Presentation layer Business Logic layer Data Access layer
NodeJS Modules
NodeJS
BaaS
MongoDB
UI
Framework
Bootstrap
JS
Framework
Angular JS
JS CSS HTML
Presentation layer Business Logic layer Data Access layer
NodeJS Modules
NodeJS
BaaS
MongoDB
UI
Framework
Bootstrap
JS
Framework
Angular JS
JS CSS HTML
Back-end
o problema das
arquiteturas bloqueantes
blocking thread
Curso de Node JS Básico
“é uma plataforma para aplicações JavaScript
criada por Ryan Dahl sob o ambiente de execução
JavaScript do Chrome.
É possível utilizar bibliotecas desenvolvidas pela
comunidade através de seu gerenciador de
pacotes chamado npm”
single thread
event loop
Curso de Node JS Básico
Curso de Node JS Básico
www.nodejs.org
$ node -v
v6.11.1
Configurando o ambiente de
desenvolvimento
Adicionar uma variável de ambiente NODE_ENV no sistema operacional. 

Linux ou OSX:
1. acessar com um editor de texto qualquer e em modo super user (sudo) o arquivo .bash_profile
ou .bashrc 

2. adicionar o seguinte comando: export NODE_ENV=’development 

No Windows:
1. Clique com botão direito no ícone Meu Computador e selecione a opção Propriedades

2. Clique em Configurações avançadas do sistema. 

3. Na janela seguinte, acesse a aba Avançado e clique no botão Variáveis de Ambiente. 

4. No campo Variáveis do sistema clique no botão Novo. 

5. Em nome da variável digite NODE_ENV e em valor da variável digite: development.
$ node
> console.log('Hello World')
Hello World
undefined
>
npm
Node Package Manager
npm
• Gerenciador de pacotes do node.js;

• Similar ao Maven do Java ou ao Gems do Ruby;
• Foi integrado ao instalador do Node.js a partir da versão
0.6.
npm install nome_do_módulo: instala um módulo no projeto;

npm install -g nome_do_módulo: instala um módulo global;

npm install nome_do_módulo --save: instala o módulo no projeto,
atualizando o package.json na lista de dependências;

npm list: lista todos os módulos do projeto;

npm list -g: lista todos os módulos globais;
Comandos Principais (npm)
npm remove nome_do_módulo: desinstala um módulo do projeto;

npm remove -g nome_do_módulo: desinstala um módulo global;

npm update nome_do_módulo: atualiza a versão do módulo;

npm update -g nome_do_módulo: atualiza a versão do módulo global;

Comandos Principais (npm)
Comandos Principais (npm)
npm -v: exibe a versão atual do npm;

npm adduser nome_do_usuário: cria uma conta no npm, através do site
https://npmjs.org.

npm whoami: exibe detalhes do seu per l público npm (é necessário
criar uma conta antes);

npm publish: publica um módulo no site do npm (é necessário ter uma
conta antes).
$ npm -v
v3.10.8
node modules
node modules
Todo projeto Node.js é chamado de módulo; 

O termo módulo, biblioteca e framework possuem o
mesmo significado (na prática);

O termo módulo surgiu do conceito de que a arquitetura do
Node.js é modular;

Todo módulo é acompanhado de um arquivo descritor
(package.json).
package.json
{
"name": "winter-is-coming—node-app",
"description": "Meu primeiro app na Muralha",
"author": "Jon Snow <jonsnow@norte.com>",
"version": "1.2.3",
"private": true,
"dependencies": {
"modulo-1": "1.0.0",
"modulo-2": "~1.0.0",
"modulo-3": ">=1.0.0"
},
"devDependencies": {
"modulo-4": "*"
}
}
CommonJS
CommonJS
• O Node.js utiliza nativamente o padrão CommonJS para
organização e carregamento de módulos;

• Para criar um código Javascript que seja modular e
carregável pelo require, utilizam-se as variáveis globais:
exports ou module.exports.
hello.js human.js
Em hello.js carregamos uma
única função modular;
Em human.js é carregado
um objeto com funções
modulares.
app.js
module.exports = function(msg) {
console.log(msg);
};
exports.hello = function(msg) {
console.log(msg);
};
var hello = require(’./hello’);
var human = require(’./human’);
hello(’Olá pessoal!’);
human.hello(’Olá galera!’);
Exercícios
node modules
1. Crie uma pasta com o nome: node-exemplos

2. Crie um arquivo com o nome retangulo.js
3. Execute execute a aplicação com o comando: node retangulo.js
var rect = {
perimeter: function (x, y) {
return (2*(x+y));
},
area: function (x, y) {
return (x*y);
}
};
function solveRect(l,b) {
console.log("Solving for rectangle with l = " + l + " and b = " + b);
if (l < 0 || b < 0) {
console.log("Rectangle dimensions should be greater than zero: l = "
+ l + ", and b = " + b);
}
else {
console.log("The area of a rectangle of dimensions length = "
+ l + " and breadth = " + b + " is " + rect.area(l,b));
console.log("The perimeter of a rectangle of dimensions length = "
+ l + " and breadth = " + b + " is " + rect.perimeter(l,b));
}
}
solveRect(2,4);
solveRect(3,5);
solveRect(-3,5);
1. Crie um novo arquivo com o nome retangulo-1.js
exports.perimeter = function (x, y) {
return (2*(x+y));
}
exports.area = function (x, y) {
return (x*y);
}
2. Crie um novo arquivo com o nome solucao-1.js
var rect = require('./retangulo-1');
function solveRect(l,b) {
console.log("Solving for rectangle with l = " + l + " and b = " + b);
if (l < 0 || b < 0) {
console.log("Rectangle dimensions should be greater than zero: l = "
+ l + ", and b = " + b);
}
else {
console.log("The area of a rectangle of dimensions length = "
+ l + " and breadth = " + b + " is " + rect.area(l,b));
console.log("The perimeter of a rectangle of dimensions length = "
+ l + " and breadth = " + b + " is " + rect.perimeter(l,b));
}
}
solveRect(2,4);
solveRect(3,5);
solveRect(-3,5);
3. Execute execute a aplicação com o comando: node solucao-1
Callbacks e
Tratamento de Erros
node modules
JavaScript e funções como
parâmetro
function falar(palavra) {
console.log(palavra);
}
function executar(funcao, valor) {
funcao(valor);
}
executar(falar, "Oi JavaScript!”);
$ node
> function falar(palavra){
... console.log(palavra);
... }
undefined
> function executar(funcao, valor){
... funcao(valor);
... }
undefined
> executar(falar, "Oi JavaScript!");
Oi JavaScript!
undefined
>
Processo 3
Processo 2
I/O (Processo Lento)
Processo 1
Processo 3
Callback
I/O (Processo Lento)
Processo 1
AssíncronoSíncrono
Curso de Node JS Básico
Exercícios
Callbacks e Tratamento de Erros
module.exports = function(x,y,callback) {
try {
if (x < 0 || y < 0) {
throw new Error("Rectangle dimensions should be greater than zero: l = "
+ x + ", and b = " + y);
}
else
callback(null, {
perimeter: function () {
return (2*(x+y));
},
area:function () {
return (x*y);
}
});
}
catch (error) {
callback(error,null);
}
}
1. Crie um arquivo com o nome retangulo-2.js
var rect = {
perimeter: function () {
return (2*(x+y));
},
area:function () {
return (x*y);
}
module.exports = function(x,y,callback) {
try {
if (x < 0 || y < 0) {
throw new Error("Rectangle dimensions should be greater than zero: l = "
+ x + ", and b = " + y);
}
else
callback(null, rect);
}
catch (error) {
callback(error,null);
}
}
1. Crie um arquivo com o nome retangulo-2.js
var rect = require('./retangulo-2');
function solveRect(l,b) {
console.log("Solving for rectangle with l = "
+ l + " and b = " + b);
rect(l,b, function(err,rectangle) {
if (err) {
console.log(err);
}
else {
console.log("The area of a rectangle of dimensions length = "
+ l + " and breadth = " + b + " is " + rectangle.area());
console.log("The perimeter of a rectangle of dimensions length = "
+ l + " and breadth = " + b + " is " + rectangle.perimeter());
}
});
};
solveRect(2,4);
solveRect(3,5);
solveRect(-3,5);
2. Crie um novo arquivo com o nome solucao-2.js
3. Execute execute a aplicação com o comando: node solucao-2
var argv = require('yargs')
.usage('Usage: node $0 --l=[num] --b=[num]')
.demand(['l','b'])
.argv;
var rect = require('./retangulo-2');
function solveRect(l,b) {
console.log("Solving for rectangle with l = "
+ l + " and b = " + b);
rect(l,b, function(err,rectangle) {
if (err) {
console.log(err);
}
else {
console.log("The area of a rectangle of dimensions length = "
+ l + " and breadth = " + b + " is " + rectangle.area());
console.log("The perimeter of a rectangle of dimensions length = "
+ l + " and breadth = " + b + " is " + rectangle.perimeter());
}
});
};
solveRect(argv.l,argv.b);
1. Crie um novo arquivo com o nome solucao-3.js
3. Execute execute a aplicação com o comando: node solucao-3 --l=5 --b=6
2. Instale o yargs com o comando: npm install yargs --save
node e http
Desenvolvendo aplicações web
Node.js é multi-protocolo: HTTP, HTTPS, FTP, SSH, DNS,
TCP, UDP, WebSockets;
Toda aplicação web necessita de um servidor para
disponibilizar todos os seus recursos;

Na prática, com o Node.js você desenvolve uma aplicação
middleware;
Além de programar as funcionalidades da sua aplicação,
você também programa códigos de configuração de
infraestrutura da sua aplicação.
Alguns módulos conhecidos são: 

• Connect (https://github.com/senchalabs/connect);

• Express (http://expressjs.com);

• Geddy (http://geddyjs.org);

• CompoundJS (http://compoundjs.com);

• Sails (http://balderdashy.github.io/sails);
Esses módulos já são preparados para lidar com desde
uma infraestrutura mínima até uma mais enxuta;

E permitem trabalhar com diferentes arquiteturas e padrões. 

• RESTFul;
• Padrão MVC;

• Model-View-Controller
• e conexões real-time utilizando WebSocket;
var http = require('http');
var server = http.createServer(function(request, response){
response.writeHead(200, {"Content-Type": "text/html"});
response.write("<h1>Hello World!</h1>");
response.end();
});
server.listen(3000);
1. Crie um novo arquivo com o nome hello_server.js
2. Execute execute a aplicação com o comando: node hello_server.js
3. No seu navegador acesse o endereço http://localhost:3000
var http = require('http');
var server = http.createServer(function(request, response){
response.writeHead(200, {"Content-Type": "text/html"});
response.write("<h1>Hello World!</h1>");
response.end();
});
server.listen(3000);
O require(‘http') carrega o módulo http padrão do node
var http = require('http');
var server = http.createServer(function(request, response){
response.writeHead(200, {"Content-Type": "text/html"});
response.write("<h1>Hello World!</h1>");
response.end();
});
server.listen(3000);
A função http.createServer() é responsável por levantar um
servidor; 

O callback function(request, response) só é executada
quando o servidor recebe uma requisição. 

Event loop constantemente verifica se o servidor foi
requisitado;

Quando uma requisição é recebida, é emitido um evento para
que seja executado o callback.
var http = require('http');
var server = http.createServer(function(request, response){
response.writeHead(200, {"Content-Type": "text/html"});
response.write("<h1>Hello World!</h1>");
response.end();
});
server.listen(3000, function(){
console.log(’Servidor Hello World rodando!’);
});
Notificar quando servidor está de pé, mudamos a linha
server.listen para receber como parâmetro uma função que
faz esse aviso.
var http = require('http');
var server = http.createServer(function(request, response){
response.writeHead(200, {"Content-Type": "text/html"});
response.write("<h1>Hello World!</h1>");
response.end();
});
server.listen(3000);
Os parâmetros da requisição http podem ser obtidos através
da variável request:
• request.headers;
• request.body;
Já os dados do cabeçalho HTML podem ser atribuídos usando
o parâmetro response:
• response.writeHead(200, {"Content-Type": “text/html"});
• response.write("<h1>Hello World!</h1>");
Trabalhando com Rotas
var http = require(’http’);
var server = http.createServer(function(request, response){
response.writeHead(200, {"Content-Type": "text/html"});
if(request.url == "/"){
response.write("<h1>Página principal</h1>");
}else if(request.url == "/bemvindo"){
response.write("<h1>Bem-vindo :)</h1>");
}else{
response.write("<h1>Página não encontrada :(</h1>");
}
response.end();
});
server.listen(3000, function(){
console.log(’Servidor rodando!’);
});
Separando o HTML do
JavaScript
var http = require('http');
var fs = require('fs');
var server = http.createServer(function(request, response){
fs.readFile(__dirname + '/index.html', function(erro, html){
response.writeHeader(200, {'Content-Type': 'text/html'});
response.write(html);
response.end();
});
});
server.listen(3000, function(){
console.log('Servidor Rodando…');
});
<!DOCTYPE html>
<html>
<head>
<title>The winter is coming!</title>
</head>
<body>
<h1>Bem vindo ao Norte!</h1>
</body>
</html>
index.html
exercicio_html_javascript.js
Mãos na Massa
Implementar um Roteador de
URLs
• Crie 3 arquivos HTML simples: inverno.html, verao.html e erro.html;

• Coloque qualquer conteúdo para cada página HTML;

• Ao digitar no browser o path: /inverno deve renderizar inverno.html;

• Ao digitar no browser o path: /verao deve renderizar verao.html;

• Ao digitar qualquer path diferente de /verao e /inverno deve
renderizar erro.html;

• A leitura dos arquivos HTML deve ser assíncrona;

• A rota principal "/" deve renderizar inverno.html;
Fast, unopinionated, minimalist
web framework for Node.js
express
É um framework web light-weight criado em 2009
que ajuda na organização de sua aplicação web, na
arquitetura MVC no lado do servidor;
express
O Express é uma estrutura web de roteamento e
middlewares que tem uma funcionalidade mínima
por si só;
Um aplicativo do Express é essencialmente uma
série de chamadas de funções de middleware.
express
Funções de Middleware são funções que tem
acesso:
• Ao objeto de solicitação (req);
• O objeto de resposta (res);
• E a próxima função de middleware no ciclo
solicitação-resposta do aplicativo (next).
express
O método HTTP para o qual a função de middleware é
aplicada.
Caminho (rota) para o qual a função de middleware é
aplicada.
A função de middleware.
Argumento de retorno de chamada para a função de
middleware, chamado de "next" por convenção.
Argumento de resposta HTTP para a função de
middleware, chamado de "res" por convenção.
Argumento de solicitação HTTP para a função de
middleware, chamado de "req" por convenção
express
O método HTTP para o qual a função de middleware é
aplicada.
Caminho (rota) para o qual a função de middleware é
aplicada.
A função de middleware.
Argumento de retorno de chamada para a função de
middleware, chamado de "next" por convenção.
Argumento de resposta HTTP para a função de
middleware, chamado de "res" por convenção.
Argumento de solicitação HTTP para a função de
middleware, chamado de "req" por convenção
express
O método HTTP para o qual a função de middleware é
aplicada.
Caminho (rota) para o qual a função de middleware é
aplicada.
A função de middleware.
Argumento de retorno de chamada para a função de
middleware, chamado de "next" por convenção.
Argumento de resposta HTTP para a função de
middleware, chamado de "res" por convenção.
Argumento de solicitação HTTP para a função de
middleware, chamado de "req" por convenção
express
O método HTTP para o qual a função de middleware é
aplicada.
Caminho (rota) para o qual a função de middleware é
aplicada.
A função de middleware.
Argumento de retorno de chamada para a função de
middleware, chamado de "next" por convenção.
Argumento de resposta HTTP para a função de
middleware, chamado de "res" por convenção.
Argumento de solicitação HTTP para a função de
middleware, chamado de "req" por convenção
express
O método HTTP para o qual a função de middleware é
aplicada.
Caminho (rota) para o qual a função de middleware é
aplicada.
A função de middleware.
Argumento de retorno de chamada para a função de
middleware, chamado de "next" por convenção.
Argumento de resposta HTTP para a função de
middleware, chamado de "res" por convenção.
Argumento de solicitação HTTP para a função de
middleware, chamado de "req" por convenção
express
O método HTTP para o qual a função de middleware é
aplicada.
Caminho (rota) para o qual a função de middleware é
aplicada.
A função de middleware.
Argumento de retorno de chamada para a função de
middleware, chamado de "next" por convenção.
Argumento de resposta HTTP para a função de
middleware, chamado de "res" por convenção.
Argumento de solicitação HTTP para a função de
middleware, chamado de "req" por convenção
express
O método HTTP para o qual a função de middleware é
aplicada.
Caminho (rota) para o qual a função de middleware é
aplicada.
A função de middleware.
Argumento de retorno de chamada para a função de
middleware, chamado de "next" por convenção.
Argumento de resposta HTTP para a função de
middleware, chamado de "res" por convenção.
Argumento de solicitação HTTP para a função de
middleware, chamado de "req" por convenção
express
Funções de middleware podem executar as seguintes
tarefas:
• Executar qualquer código;
• Fazer mudanças nos objetos de solicitação e resposta;
• Encerrar o ciclo de solicitação-resposta;
• Chamar a próxima função de middleware na pilha;
• Se a atual função de middleware não terminar o ciclo
de solicitação-resposta, ela precisa chamar next().
express
Crie uma pasta para colocar o novo exemplo;
Em seguida no terminal/linha de comando navegue até a
pasta e instale o express:
express
$ npm install express --save
Express Hello World
var express = require('express'),
http = require('http');
var hostname = 'localhost';
var port = 3000;
var app = express();
app.use(function (req, res, next) {
res.writeHead(200, { 'Content-Type': 'text/html' });
res.end('<html><body><h1>Hello World</h1></body></html>');
});
var server = http.createServer(app);
server.listen(port, hostname, function(){
console.log(`Server running at http://${hostname}:${port}/`);
});
express
$ node intro-express.js
Crie um arquivo chamado intro-express.js
Para entregar arquivos estáticos como imagens,
arquivos CSS, e arquivos JavaScript, use a função de
middleware express.static;
Passe o nome do diretório que contém os ativos
estáticos para a função de middleware express.static
para iniciar a entregar os arquivos diretamente;
Por exemplo, use o código a seguir para entregar
imagens, arquivos CSS, e arquivos JavaScript em um
diretório chamado public.
express
Agora, é possível carregar os arquivos que estão no
diretório public:
express
app.use(express.static('public'));
http://localhost:3000/images/kitten.jpg
http://localhost:3000/css/style.css
http://localhost:3000/js/app.js
http://localhost:3000/images/bg.png
http://localhost:3000/hello.html
Serving Static Content
Crie uma pasta chamada public e coloque dentro dois
arquivos html quaisquer;

var express = require('express');
var hostname = 'localhost';
var port = 3000;
var app = express();
app.use(express.static(__dirname + '/public'));
app.listen(port, hostname, function(){
console.log(`Server running at http://${hostname}:${port}/`);
});
express
REST
Representational State Transfer (REST)
Representational State Transfer (REST) or RESTful
web services é uma maneira simples de organizar
interações em sistemas independentes.
Proporcionando interoperabilidade entre o sistema
e os diversos dispositivos com acesso a Internet.
Os serviços da Web compatíveis com REST
permitem que os sistemas solicitantes acessem e
manipulem representações textuais de recursos
da Web usando um conjunto uniforme e predefinido
de operações stateless.
Os princípios fundamentais do REST envolvem separar sua
API em recursos lógicos. 

Esses recursos são manipulados usando solicitações
HTTP nas quais o método (GET, POST, PUT, PATCH ou
DELETE) tem um significado específico.

Recursos devem ser substantivos (não verbos!) que fazem
sentido do ponto de vista do quem vai “consumir” a AP
Depois da definição dos recursos, é necessário identificar
quais ações se aplicam a eles e como serão mapeados para
a API. 

Princípios RESTful fornecem estratégias para lidar com
ações CRUD usando métodos HTTP mapeados, tal como:

• GET /tickets Retorna a lista de bilhetes

• GET /tickets/12 Retorna um bilhete específico

• POST /tickets Cria um novo bilhete

• PUT /tickets/12 Atualiza o bilhete #12

• PATCH /tickets/12 Atualiza parcialmente o bilhete #12

• DELETE /tickets/12 Apaga o bilhete #12
A grande vantagem em REST é que se está aproveitando
métodos HTTP existentes para implementar funcionalidades
significativas em apenas um único endpoint /tickets;

Não existem convenções de nomenclatura a seguir e a
estrutura de URL é limpa e clara.

RESPOSTAS SEMPRE EM JSON!!!!
Curso de Node JS Básico
Roteamento
O Roteamento refere-se à determinação de como um
aplicativo responde a uma solicitação do cliente por um
endpoint específico;

A solicitação é compostas por uma URI (ou caminho) e um
método de solicitação HTTP específico (GET, POST, e assim
por diante);

Cada rota pode ter uma ou mais funções de manipulação,
que são executadas quando a rota é correspondida.
A definição de rotas aceita a seguinte estrutura:

Onde:

app é uma instância do express;

METHOD é um método de solicitação HTTP;

PATH é um caminho no servidor;

HANDLER é a função executada quando a rota é
correspondida.
app.METHOD(PATH, HANDLER)
app.get('/', function (req, res) {
res.send('Hello World!');
});
Responde uma requisição GET com Hello
World! na página inicial.
app.post('/', function (req, res) {
res.send('Got a POST request');
});
Responder a uma solicitação POST na rota raiz
(/) com a página inicial do aplicativo.
app.put('/user', function (req, res) {
res.send('Got a PUT request at /user');
});
Responder a uma solicitação PUT para a rota 

/user.
app.delete('/user', function (req, res) {
res.send('Got a DELETE request at /user');
});
Responder a uma solicitação DELETE para a
rota /user.
Exercício
Implemente as seguintes rotas:
var express = require('express');
var morgan = require('morgan');
var bodyParser = require('body-parser');
var hostname = 'localhost';
var port = 3000;
var app = express();
app.use(morgan('dev'));
app.use(bodyParser.json());
app.all('/books', function(req,res,next) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
next();
});
app.get('/books', function(req,res,next){
res.end('Will send all the books to you!');
});
app.get('/books/:bookId', function(req,res,next){
res.end('Will send details of the book: ' + req.params.bookId +' to you!');
});
. . .
app.listen(port, hostname, function(){
console.log(`Server running at http://${hostname}:${port}/`);
});
Roteamento
express.Router
Use a classe express.Router para criar manipuladores
de rota modulares e montáveis. 

Uma instância de Router é um middleware e sistema de
roteamento completo; 

Por essa razão, é frequentemente tratado como um “mini-
aplicativo”
var express = require('express');
var router = express.Router();
router.use(function timeLog(req, res, next) {
console.log('Time: ', Date.now());
next();
});
router.get('/', function(req, res) {
res.send('Winter is Comming Home page');
});
router.get('/about', function(req, res) {
res.send('Tratar com Jon Snow');
});
module.exports = router;
Crie um arquivo de roteador com um arquivo
chamado winter.js no diretório do aplicativo, com o
seguinte conteúdo:
var express = require('express');
var hostname = 'localhost';
var port = 3000;
var app = express();
var winter = require('./winter');
app.use('/winters', winter);
app.listen(port, hostname, function(){
console.log(`Server running at http://${hostname}:${port}/`);
});
Crie um arquivo de roteador com um arquivo
chamado winter-server.js no diretório do aplicativo, com
o seguinte conteúdo:
Exercício
Agora atualize seu código para utilizar o express.Router e
implemente as seguintes rotas:
Express Generator
Express Generator
Usado criar rapidamente uma estrutura básica de projeto;
Instale o express generator com o comando a seguir:
$ npm install express-generator -g
$ express --view=pug things-app
create : things-app
create : things-app/package.json
create : things-app/app.js
create : things-app/public
create : things-app/public/javascripts
create : things-app/public/images
create : things-app/routes
create : things-app/routes/index.js
create : things-app/routes/users.js
create : things-app/public/stylesheets
create : things-app/public/stylesheets/style.css
create : things-app/views
create : things-app/views/index.pug
create : things-app/views/layout.pug
create : things-app/views/error.pug
create : things-app/bin
create : things-app/bin/www
!"" app.js
!"" bin
# $"" www
!"" package.json
!"" public
# !"" images
# !"" javascripts
# $"" stylesheets
# $"" style.css
!"" routes
# !"" index.js
# $"" users.js
$"" views
!"" error.pug
!"" index.pug
$"" layout.pug
7 directories, 9 files
O aplicativo gerado possui a
seguinte estrutura de diretórios:
app.js: starting application
package.json
public: static resources
routes: application routes
views: template engine templates
Exercício
Nesta tarefa você continuará a exploração de módulos Node, Express e API REST. 

Você deve:

Criar um módulo usando o Express Router para suportar as rotas para os waters
REST API.

Criar um módulo usando o Express Router para suportar as rotas para os
temperatures REST API.

Criar um módulo usando o Express Router para suportar as rotas para os energy
REST API.

http://localhost:3000/waters

http://localhost:3000/temperatures

http://localhost:3000/energy

É necessário suportar as operações GET, PUT, POST e DELETE em cada um dos
três endpoints, incluindo o suporte ao uso de parâmetros de rota para identificar um
registro específico.
Banco de Dados
SQL
NoSQL
Cada paradigma apresentado ataca
problemas diferentes e sua escolha
não é uma decisão puramente
preferencial, mas de necessidade do
projeto, tangendo aspectos
arquiteturais e mais abstratos
Curso de Node JS Básico
Curso de Node JS Básico
Curso de Node JS Básico
O MongoDB é um banco de dados baseado em
documento com alta performance e
disponibilidade e de fácil escalabilidade
Document: informação completa e “autocontida”;
JSON document:

{“name”: “Uthapizza”, 

”description”: “A unique combination . . .”}
Collection: coleção de documentos;
Database: conjunto de coleções.
database
O conceito de documento
Um documento pode ser armazenado em diferentes
formatos hierárquicos como XML ou JSON com os dados
associados a uma estrutura de chave e valor. 

É através de uma chave específica do documento que
temos acesso ao valor associado.
O conceito de documento
O MongoDB armazena seus documentos no formato BSON
(Binary JSON), muito parecido com JSON. Comparemos a
estrutura desses dois formatos:
// JSON
{
"nome" : "Jon Snow"
}
// BSON
{
"_id" : ObjectId("5303e0649fd1396")
"nome" : "Jon Snow"
}
Diferença entre BSON e JSON
É a quantidade dos tipos de dados suportados em cada
uma deles: 

JSON: 6 tipos (Array, Boolean, null, Number, Object e
String) 

BSON: +15 tipos
Tipos de Dados (BSON)
ObjectId
Todo documento criado recebe automaticamente a chave _id
contendo como valor padrão um objeto do tipo ObjectId.

• São pequenos;

• Provavelmente únicos;

• Rápidos para gerar e ordenados;

• Consistem de 12 bytes;

• Os 4 primeiros são um timestamp que reflete o momento
da criação.
Instalação
https://docs.mongodb.com/manual/installation/
É altamente recomendável utilizar a versão de 64 Bits
em produção pelo fato de o banco na versão de 32
Bits ser limitado a um tamanho de no máximo dois
gigabytes.
Curso de Node JS Básico
Criando e Rodando o Banco
Uma forma testar a instalação do MongoDB é coma cliente
de linha de comando: o mongo shell
Abra uma nova janela do terminal (sem fechar) e execute o
seguinte comando:
$ mongod --dbpath <path>
$ mongo
Curso de Node JS Básico
Criando uma nova base de
dados
No terminal executando o “mongo shell” rode o comando:
Em execute o comando db para verificar qual base de
dados está sendo usada
> db
things
> use things
Criando uma nova coleção
No terminal executando o “mongo shell” rode o comando:
Se uma coleção não existe, o MongoDB cria a
coleção quando ele salva os dados pela primeira vez.
> db.myNewCollection.insertOne( { x: 1 } )
> db.myNewCollection2.createIndex( { y: 1 } )
MongoDB CRUD (Create)
MongoDB fornece os seguintes métodos para inserir
documentos em uma coleção:

db.collection.insertOne() 

db.collection.insertMany()
MongoDB CRUD (Read)
Operações de leitura recuperam documentos de uma
coleção;
MongoDB CRUD (Update)
MongoDB fornece os seguintes métodos para atualizar
documentos de uma coleção:

db.collection.updateOne() 

db.collection.updateMany()

db.collection.replaceOne()
MongoDB CRUD (Delete)
O MongoDB fornece os seguintes métodos para excluir
documentos de uma coleção:

db.collection.deleteOne() 

db.collection.deleteMany()
Curso de Node JS Básico
É preciso que a aplicação seja capaz de se conectar e realizar
operações no banco de dados;
Para isso MongoDB possui um driver nativo, criado especialmente
para o Node.js;
Sua instalação é feita através do npm como qualquer outro módulo
do Node.js:
https://github.com/mongodb/node-mongodb-native
npm install mongodb --save
Conectando ao mongoDB
var MongoClient = require('mongodb').MongoClient
, co = require('co')
, assert = require('assert');
// 1. Connect to MongoDB instance running on localhost
// Connection URL
var url = 'mongodb://localhost:27017/test';
co(function*() {
const db = yield MongoClient.connect(url);
console.log("Connected successfully to server");
yield insertDocuments(db, null);
yield findDocuments(db, null);
yield indexCollection(db, null);
yield aggregateDocuments(db, null);
db.close();
}).catch(err => console.log(err));
Inserindo no Banco
var insertDocuments = function(db, callback) {
return co(function*() {
const results = yield db.collection('restaurants')
.insertMany( [
{“name":"Sun Trattoria", "stars":4, "categories":["Pizza","Pasta","Italian","Coffee"]},
{"name":"Blue Bagels Grill", "stars":3, "categories":["Bagels","Cookies","Sandwiches"]},
{"name":"Hot Bakery Cafe","stars":4,"categories":["Bakery","Cafe","Coffee","Dessert"]},
{"name":"XYZ Coffee Bar","stars":5,"categories":["Coffee","Cafe","Bakery","Chocolates"]},
{"name":"456 Cookies Shop","stars":4,"categories":["Bakery","Cookies","Cake","Coffee"]}
]);
console.log(results)
return results;
});
}
Fazendo uma Busca no Banco
var findDocuments = function(db) {
return co(function*() {
// Get the documents collection
const collection = db.collection('restaurants');
const docs = yield collection.find({}).toArray();
console.log("Found the following records");
console.log(docs)
return docs;
});
}
Exercício
Exercício
Crie uma nova base de dados para o seu projeto;

A base deve conter no mínimo 5 coleções;

cada coleção deve representar o conjunto de informações
gerados por um sensor diferente (ex: sensor que monitora a
água da casa, a energia…);

Popule as coleções com dados “fake";

Faça consultas para extrair informações importantes da
base de dados.
Exercício
Crie um novo módulo (chamado operations.js) para o Node
contendo algumas operações comuns de MongoDB (CRUD);

Use o módulo na sua aplicação e comunique-se com o
servidor MongoDB (o módulo deve ser reaproveitável para
ser utilizado por qualquer novo “tipo” que for criado).
var assert = require('assert');
exports.insertDocument = function(db, document, collection, callback) {
// Get the documents collection
var coll = db.collection(collection);
// Insert some documents
coll.insert(document, function(err, result) {
assert.equal(err, null);
console.log("Inserted " + result.result.n + " documents into the document collection "
+ collection);
callback(result);
});
};
Curso de Node JS Básico
var assert = require('assert');
exports.insertDocument = function(db, document, collection, callback) {
// Get the documents collection
var coll = db.collection(collection);
// Insert some documents
coll.insert(document, function(err, result) {
assert.equal(err, null);
console.log("Inserted " + result.result.n + " documents into the document collection "
+ collection);
callback(result);
});
};
exports.findDocuments = function(db, collection, callback) {
// Get the documents collection
var coll = db.collection(collection);
// Find some documents
coll.find({}).toArray(function(err, docs) {
assert.equal(err, null);
callback(docs);
});
};
exports.removeDocument = function(db, document, collection, callback) {
// Get the documents collection
var coll = db.collection(collection);
// Delete the document
coll.deleteOne(document, function(err, result) {
assert.equal(err, null);
console.log("Removed the document " + document);
callback(result);
// Find some documents
coll.find({}).toArray(function(err, docs) {
assert.equal(err, null);
callback(docs);
});
};
exports.removeDocument = function(db, document, collection, callback) {
// Get the documents collection
var coll = db.collection(collection);
// Delete the document
coll.deleteOne(document, function(err, result) {
assert.equal(err, null);
console.log("Removed the document " + document);
callback(result);
});
};
exports.updateDocument = function(db, document, update, collection, callback) {
// Get the documents collection
var coll = db.collection(collection);
// Update document
coll.updateOne(document
, { $set: update }, null, function(err, result) {
assert.equal(err, null);
console.log("Updated the document with " + update);
callback(result);
});
};
var MongoClient = require('mongodb').MongoClient,
assert = require('assert');
var dboper = require('./operations');
var url = 'mongodb://localhost:27017/conFusion';
MongoClient.connect(url, function (err, db) {
assert.equal(null, err);
console.log("Connected correctly to server");
dboper.insertDocument(db, { name: "Vadonut", description: "Test" },
"dishes", function (result) {
console.log(result.ops);
dboper.findDocuments(db, "dishes", function (docs) {
console.log(docs);
dboper.updateDocument(db, { name: "Vadonut" },
{ description: "Updated Test" },
"dishes", function (result) {
console.log(result.result);
dboper.findDocuments(db, "dishes", function (docs) {
console.log(docs)
db.dropCollection("dishes", function (result) {
console.log(result);
db.close();
});
});
});
});
});
});
mongooseLet's face it, writing MongoDB validation, casting and business logic boilerplate
is a drag. That's why we wrote Mongoose.
O Mongoose é um módulo focado para a criação de
models, isso significa que com ele criaremos objetos
persistentes modelando seus atributos através do objeto
mongoose.Schema.
mongoose
Instalação…
mongoose
$ npm install mongoose --save
mongoose
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
// create a schema
var thingSchema = new Schema({
name: {
type: String,
required: true,
unique: true
},
description: {
type: String,
required: true
}
}, {
timestamps: true
});
var things = mongoose.model('thing', thingSchema);
// make this available to our Node applications
module.exports = things;
mongoose var mongoose = require('mongoose'),
assert = require('assert');
var things = require('./things');
// Connection URL
var url = 'mongodb://localhost:27017/db_things';
mongoose.connect(url);
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function () {
console.log("Connected correctly to server");
// create a new user
var newThing = things({
name: 'Cadeira',
description: 'Cadeira Inteligente'
});
// save the user
newThing.save(function (err) {
if (err) throw err;
console.log('thing created!');
things.find({}, function (err, things) {
if (err) throw err;
console.log(things);
db.close();
// });
});
});
});
Schemas “Composto"
mongoose
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var commentSchema = new Schema({
rating: {
type: Number,
min: 1,
max: 5,
required: true
},
comment: {
type: String,
required: true
},
author: {
type: String,
required: true
}
}, {
timestamps: true
});
. . .
. . .
var thingSchema = new Schema({
name:{
type:String,
required:true,
unique:true
},
description:{
type:String,
required:true
},
comments:[commentSchema]
}, {
timestamps:true
});
var Things = mongoose.model('thing', thingSchema);
module.exports = Things;
mongoose var mongoose = require('mongoose');
var assert = require('assert');
var Things = require('./models/things-2.js');
var url = 'mongodb://localhost:27017/conFusion';
mongoose.connect(url);
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function(){
console.log("Connected correctly to server");
// create a new user
var newThing = Things({
name: 'Cadeira Legal',
description: 'cadeira mágica',
comments: [
{
rating: 3,
comment: 'This is insane',
author: 'Matt Daemon'
}
]
});
newThing.save(function(err, thing){
if (err) throw err;
console.log('Thing created!');
console.log(thing);
var id = thing._id;
setTimeout(function(){
Things.findByIdAndUpdate(id, {
$set:{
description: 'udpated test'
}
mongoose
if (err) throw err;
console.log('Thing created!');
console.log(thing);
var id = thing._id;
setTimeout(function(){
Things.findByIdAndUpdate(id, {
$set:{
description: 'udpated test'
}
}, {
new:true
}).exec(function(err,thing){
if (err) throw err;
console.log('Updated thing!');
console.log(thing);
thing.comments.push({
rating: 5,
comment: 'I'm getting a sinking feeling!',
author: 'Leonardo di Carpaccio'
});
thing.save(function (err, thing) {
console.log('Updated Comments!');
console.log(thing);
db.collection('things').drop(function () {
db.close();
});
});
});
}, 3000);
});
});
Exercício
• Usando o express-generator crie um novo projeto de sua
escolha;

• Nesse projeto você deve criar 3 schemas do mongoose,
sendo que pelo menos um deles será utilizado como "sub
schema” do outro;

• Crie um controller para cada um dos schemas, cada
controle deve conter operações de CRUD dos schemas;

• Crie um arquivo javascript para chamar e testar os
controllers;
REST API
com Express, MongoDB and Mongoose
Curso de Node JS Básico
mongooseexpress
REST API
Toda requisição precisa ser decodificada e em seguida
mapeada de acordo com sua “natureza”:
Router().route(’/uri’)
.get(
)
.post (
)
Mongoose Schema + MongoDB
Things.find({},
);
Things.create(
);
REST API
Toda requisição precisa ser decodificada e em seguida
mapeada de acordo com sua “natureza”:
Crie o projeto utilizando o express-generator:
$ express --view=pug rest-api-exercise
create : rest-api-exercise
create : rest-api-exercise/package.json
create : rest-api-exercise/app.js
create : rest-api-exercise/public
create : rest-api-exercise/views
create : rest-api-exercise/views/index.pug
create : rest-api-exercise/views/layout.pug
create : rest-api-exercise/views/error.pug
create : rest-api-exercise/routes
create : rest-api-exercise/routes/index.js
create : rest-api-exercise/routes/users.js
create : rest-api-exercise/bin
create : rest-api-exercise/bin/www
create : rest-api-exercise/public/javascripts
create : rest-api-exercise/public/images
create : rest-api-exercise/public/stylesheets
create : rest-api-exercise/public/stylesheets/style.css
$ npm install
$ npm install mongoose mongoose-currency --save
Instale os módulos node necessários:
Crie a pasta models e dentro dela o schema books.js
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
// add the Currency type to the Mongoose Schema types
require('mongoose-currency').loadType(mongoose);
var Currency = mongoose.Types.Currency;
var commentSchema = new Schema({
rating: { type: Number, min: 1, max: 5, required: true },
comment: { type: String, required: true },
author: {type: String, required: true}
},
{ timestamps: true}
);
var bookSchema = new Schema({
name:{ type:String, required:true, unique:true },
image:{ type:String, required:true },
category:{ type:String, required:true },
label: { type: String, default: '' },
price: { type:Currency },
description:{ type:String, required:true },
comments:[commentSchema]
},
{ timestamps:true }
);
var Books = mongoose.model('Book', bookSchema);
module.exports = Books;
Dentro da pasta routes crie o arquivo bookRouter.js
var express = require('express');
var bodyParser = require('body-parser');
var mongoose = require('mongoose');
var Books = require('../models/books');
var bookRouter = express.Router();
bookRouter.use(bodyParser.json());
bookRouter.route('/')
.get(function (req, res, next) {
Books.find({}, function (err, book) {
if (err) throw err;
res.json(book);
});
})
.post(function (req, res, next) {
Books.create(req.body, function (err, book) {
if (err) throw err;
console.log('Book created!');
var id = book._id;
res.writeHead(200, {
'Content-Type': 'text/plain'
});
res.end('Added the book with id: ' + id);
});
})
.delete(function (req, res, next) {
Books.remove({}, function (err, resp) {
if (err) throw err;
res.json(resp);
.delete(function (req, res, next) {
Books.remove({}, function (err, resp) {
if (err) throw err;
res.json(resp);
});
});
bookRouter.route('/:bookId')
.get(function (req, res, next) {
Books.findById(req.params.bookId, function (err, book) {
if (err) throw err;
res.json(book);
});
})
.put(function (req, res, next) {
Books.findByIdAndUpdate(req.params.bookId, {
$set: req.body
}, {
new: true
}, function (err, book) {
if (err) throw err;
res.json(book);
});
})
.delete(function (req, res, next) {
Books.findByIdAndRemove(req.params.bookId, function (err, resp) { if (err) throw err;
res.json(resp);
});
});
bookRouter.route('/:bookId/comments')
.get(function (req, res, next) {
Books.findById(req.params.bookId, function (err, book) {
if (err) throw err;
res.json(book.comments);
});
})
bookRouter.route('/:bookId/comments')
.get(function (req, res, next) {
Books.findById(req.params.bookId, function (err, book) {
if (err) throw err;
res.json(book.comments);
});
})
.post(function (req, res, next) {
Books.findById(req.params.bookId, function (err, book) {
if (err) throw err;
book.comments.push(req.body);
book.save(function (err, book) {
if (err) throw err;
console.log('Updated Comments!');
res.json(book);
});
});
})
.delete(function (req, res, next) {
Books.findById(req.params.bookId, function (err, book) {
if (err) throw err;
for (var i = (book.comments.length - 1); i >= 0; i--) {
book.comments.id(book.comments[i]._id).remove();
}
book.save(function (err, result) {
if (err) throw err;
res.writeHead(200, {
'Content-Type': 'text/plain'
});
res.end('Deleted all comments!');
});
});
});
bookRouter.route('/:bookId/comments/:commentId')
.get(function (req, res, next) {
Books.findById(req.params.bookId, function (err, book) {
if (err) throw err;
bookRouter.route('/:bookId/comments/:commentId')
.get(function (req, res, next) {
Books.findById(req.params.bookId, function (err, book) {
if (err) throw err;
res.json(book.comments.id(req.params.commentId));
});
})
.put(function (req, res, next) {
// We delete the existing commment and insert the updated
// comment as a new comment
Books.findById(req.params.bookId, function (err, book) {
if (err) throw err;
book.comments.id(req.params.commentId).remove();
book.comments.push(req.body);
book.save(function (err, book) {
if (err) throw err;
console.log('Updated Comments!');
res.json(book);
});
});
})
.delete(function (req, res, next) {
Books.findById(req.params.bookId, function (err, book) {
book.comments.id(req.params.commentId).remove();
book.save(function (err, resp) {
if (err) throw err;
res.json(resp);
});
});
});
module.exports = bookRouter;
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 index = require('./routes/index');
var users = require('./routes/users');
var bookRouter = require('./routes/bookRouter');
var mongoose = require('mongoose');
var url = 'mongodb://localhost:27017/books';
mongoose.connect(url);
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function () {
// we're connected!
console.log("Connected correctly to server");
});
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
Ajuste o arquivo app.js criado pelo express-generator
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', index);
app.use('/books', bookRouter);
app.use('/users', users);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
Testando…
Curso de Node JS Básico
Exercício
Agora continuando o exemplo, crie uma rota, schema e API
similar a criada para os “tipos" CD e Obra de Arte.
Basic Authentication
Client Serverrequest a protected resource
request username and password
send username and password
returns requested resource
Express and Basic
Authentication
function auth (req, res, next) {
console.log(req.headers);
var authHeader = req.headers.authorization;
if (!authHeader) {
var err = new Error('You are not authenticated!');
err.status = 401;
next(err);
return;
}
var auth = new Buffer(authHeader.split(' ')[1], 'base64').toString().split(':');
var user = auth[0];
var pass = auth[1];
if (user == 'admin' && pass == 'password') {
next(); // authorized
} else {
var err = new Error('You are not authenticated!');
err.status = 401;
next(err);
}
}
app.use(auth);
var express = require('express');
var morgan = require('morgan');
var hostname = 'localhost';
var port = 3000;
var app = express();
app.use(morgan('dev'));
function auth (req, res, next) {
console.log(req.headers);
var authHeader = req.headers.authorization;
if (!authHeader) {
var err = new Error('You are not authenticated!');
err.status = 401;
next(err);
return;
}
var auth = new Buffer(authHeader.split(' ')[1], 'base64').toString().split(':');
var user = auth[0];
var pass = auth[1];
if (user == 'admin' && pass == 'password') {
next(); // authorized
} else {
var err = new Error('You are not authenticated!');
err.status = 401;
next(err);
}
}
Express and Basic Authentication
app.use(morgan('dev'));
function auth (req, res, next) {
console.log(req.headers);
var authHeader = req.headers.authorization;
if (!authHeader) {
var err = new Error('You are not authenticated!');
err.status = 401;
next(err);
return;
}
var auth = new Buffer(authHeader.split(' ')[1], 'base64').toString().split(':');
var user = auth[0];
var pass = auth[1];
if (user == 'admin' && pass == 'password') {
next(); // authorized
} else {
var err = new Error('You are not authenticated!');
err.status = 401;
next(err);
}
}
app.use(auth);
app.use(express.static(__dirname + '/public'));
app.use(function(err,req,res,next) {
res.writeHead(err.status || 500, {
'WWW-Authenticate': 'Basic',
'Content-Type': 'text/plain'
});
res.end(err.message);
});
app.listen(port, hostname, function(){
console.log(`Server running at http://${hostname}:${port}/`);
});
Exercício
Agora continuando o exemplo, continue o exercício de
criação da REST API colocando o controle de acesso aos
métodos dos routers.
User Authentication
with Passport
User Authentication with
Passport
Passport (http://passportjs.og) é uma solução não
obstrusiva de autenti- cação especí ca para o Node.js que
dá suporte a vários provedores como o Facebook, Twiiter,
Google entre outros
app.post('/login',
passport.authenticate('local', { successRedirect: '/',
failureRedirect: '/login' }));
Apesar das complexidades envolvidas na autenticação, o código
não precisa ser complicado
app.post('/login',
passport.authenticate('local'),
function(req, res) {
// If this function gets called, authentication was successful.
// `req.user` contains the authenticated user.
res.redirect('/users/' + req.user.username);
});
Os pedidos de autenticação são tão simples como chamar
passport.authenticate () e especificar qual estratégia empregar.
Se a autenticação falhar, o Passport responderá com um status 401
não autorizado e todos os manipuladores de rotas adicionais não
serão invocado
app.post('/login',
passport.authenticate('local', { successRedirect: '/',
failureRedirect: '/login' }));
Um redirecionamento geralmente é emitido após a autenticação
de um pedido.
Nesse caso, as opções de redirecionamento substituem o
comportamento padrão. Após a autenticação bem-sucedida,
o usuário será redirecionado para a página inicial. Se a
autenticação falhar, o usuário será redirecionado de volta
para a página de login para outra tentativa.
- app
------ models
---------- user.js <!-- our user model -->
------ routes.js <!-- all the routes for our application -->
- config
------ auth.js <!-- will hold all our client secret keys (facebook, twitter, google) -->
------ database.js <!-- will hold our database connection settings -->
------ passport.js <!-- configuring the strategies for passport -->
- views
------ index.ejs <!-- show our home page with login links -->
------ login.ejs <!-- show our login form -->
------ signup.ejs <!-- show our signup form -->
------ profile.ejs <!-- after a user logs in, they will see their profile -->
- package.json <!-- handle our npm packages -->
- server.js <!-- setup our application -->
Primeiro vamos criar um novo projeto com a
seguinte estrutura:
{
"name": “passaport-authentication",
"main": "server.js",
"dependencies" : {
"express" : "latest",
"ejs" : "latest",
"mongoose" : "latest",
"passport" : "latest",
"passport-local" : "latest",
"passport-facebook" : "latest",
"passport-twitter" : "latest",
"passport-google-oauth" : "latest",
"connect-flash" : "latest",
"bcrypt-nodejs" : "latest",
"body-parser": "latest",
"cookie-parser": "latest",
"debug": "latest",
"morgan": "latest",
"serve-favicon": "latest",
"express-session":"latest"
}
}
package.json
// app/models/user.js
var mongoose = require('mongoose');
var bcrypt = require('bcrypt-nodejs');
var userSchema = mongoose.Schema({
local : {
email : String,
password : String,
}
});
userSchema.methods.generateHash = function(password) {
return bcrypt.hashSync(password, bcrypt.genSaltSync(8), null);
};
userSchema.methods.validPassword = function(password) {
return bcrypt.compareSync(password, this.local.password);
};
module.exports = mongoose.model('User', userSchema);
// app/routes.js
module.exports = function(app, passport) {
app.get('/', function(req, res) {
res.render('index.ejs');
});
app.get('/login', function(req, res) {
res.render('login.ejs', { message: req.flash('loginMessage') });
});
app.post('/login', passport.authenticate('local-login', {
successRedirect : '/profile',
failureRedirect : '/login',
failureFlash : true
}));
app.get('/signup', function(req, res) {
res.render('signup.ejs', { message: req.flash('signupMessage') });
});
app.post('/signup', passport.authenticate('local-signup', {
successRedirect : '/profile',
failureRedirect : '/signup',
failureFlash : true
}));
app.get('/profile', isLoggedIn, function(req, res) {
res.render('profile.ejs', {
user : req.user
});
});
failureRedirect : '/login',
failureFlash : true
}));
app.get('/signup', function(req, res) {
res.render('signup.ejs', { message: req.flash('signupMessage') });
});
app.post('/signup', passport.authenticate('local-signup', {
successRedirect : '/profile',
failureRedirect : '/signup',
failureFlash : true
}));
app.get('/profile', isLoggedIn, function(req, res) {
res.render('profile.ejs', {
user : req.user
});
});
app.get('/logout', function(req, res) {
req.logout();
res.redirect('/');
});
};
function isLoggedIn(req, res, next) {
if (req.isAuthenticated())
return next();
res.redirect('/');
}
// config/passport.js
var LocalStrategy = require('passport-local').Strategy;
var User = require('../app/models/user');
module.exports = function(passport) {
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
passport.use('local-signup', new LocalStrategy({
usernameField : 'email',
passwordField : 'password',
passReqToCallback : true
},
function(req, email, password, done) {
User.findOne({ 'local.email' : email }, function(err, user) {
if (err)
return done(err);
if (user) {
return done(null, false, req.flash('signupMessage', 'That email is already taken.'));
} else {
var newUser = new User();
newUser.local.email = email;
newUser.local.password = newUser.generateHash(password);
newUser.save(function(err) {
if (err)
throw err;
return done(null, newUser);
});
passwordField : 'password',
passReqToCallback : true
},
function(req, email, password, done) {
User.findOne({ 'local.email' : email }, function(err, user) {
if (err)
return done(err);
if (user) {
return done(null, false, req.flash('signupMessage', 'That email is already taken.'));
} else {
var newUser = new User();
newUser.local.email = email;
newUser.local.password = newUser.generateHash(password);
newUser.save(function(err) {
if (err)
throw err;
return done(null, newUser);
});
}
});
}));
passport.use('local-login', new LocalStrategy({
usernameField : 'email',
passwordField : 'password',
passReqToCallback : true
},
function(req, email, password, done) {
User.findOne({ 'local.email' : email }, function(err, user) {
if (err)
return done(err);
if (!user)
return done(null, false, req.flash('loginMessage', 'No user found.'));
if (!user.validPassword(password))
return done(null, false, req.flash('loginMessage', 'Oops! Wrong password.'));
newUser.local.password = newUser.generateHash(password);
newUser.save(function(err) {
if (err)
throw err;
return done(null, newUser);
});
}
});
}));
passport.use('local-login', new LocalStrategy({
usernameField : 'email',
passwordField : 'password',
passReqToCallback : true
},
function(req, email, password, done) {
User.findOne({ 'local.email' : email }, function(err, user) {
if (err)
return done(err);
if (!user)
return done(null, false, req.flash('loginMessage', 'No user found.'));
if (!user.validPassword(password))
return done(null, false, req.flash('loginMessage', 'Oops! Wrong password.'));
return done(null, user);
});
}));
};
// server.js
var express = require('express');
var port = process.env.PORT || 8080;
var mongoose = require('mongoose');
var passport = require('passport');
var flash = require('connect-flash');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var session = require('express-session')
var configDB = require('./config/database.js');
var app = express();
mongoose.connect(configDB.url);
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.set('view engine', 'ejs');
app.use(session({secret: 'winteriscomming'}))
app.use(passport.initialize());
app.use(passport.session());
app.use(flash());
//ORDEM IMPORTA!!!
require('./config/passport')(passport);
require('./app/routes.js')(app, passport);
app.listen(port);
console.log('The magic happens on port ' + port);
// config/database.js
module.exports = {
'url' : 'mongodb://localhost/passport'
};
https://goo.gl/EQPD2Z
Crie o arquivo database.js com a URL do seu banco de dados
Faça o download das views e copie para a pasta views
Curso de Node JS Básico
Entre no site "Facebook Developers" e crie a sua aplicação.
Defina a sua callback URL para:
 http://localhost:8080/auth/facebook/callback
module.exports = {
'facebookAuth' : {
'clientID' : 'your-secret-clientID-here', // App ID
'clientSecret' : 'your-client-secret-here', // App Secret
'callbackURL' : 'http://localhost:8080/auth/facebook/callback'
}
};
// config/passport.js
var LocalStrategy = require('passport-local').Strategy;
var FacebookStrategy = require('passport-facebook').Strategy;
var User = require('../app/models/user');
var configAuth = require('./auth');
module.exports = function(passport) {
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
passport.use(new FacebookStrategy({
clientID : configAuth.facebookAuth.clientID,
clientSecret : configAuth.facebookAuth.clientSecret,
callbackURL : configAuth.facebookAuth.callbackURL
},
function(token, refreshToken, profile, done) {
process.nextTick(function() {
User.findOne({ 'facebook.id' : profile.id }, function(err, user) {
if (err)
return done(err);
if (user) {
return done(null, user);
} else {
passport.use(new FacebookStrategy({
clientID : configAuth.facebookAuth.clientID,
clientSecret : configAuth.facebookAuth.clientSecret,
callbackURL : configAuth.facebookAuth.callbackURL
},
function(token, refreshToken, profile, done) {
process.nextTick(function() {
User.findOne({ 'facebook.id' : profile.id }, function(err, user) {
if (err)
return done(err);
if (user) {
return done(null, user);
} else {
var newUser = new User();
newUser.facebook.id = profile.id;
newUser.facebook.token = token;
newUser.facebook.name = profile.name.givenName + ' ' + profile.name.familyName;
newUser.facebook.email = profile.emails[0].value;
console.log(profile);
newUser.save(function(err) {
if (err)
throw err;
return done(null, newUser);
});
}
});
});
}));
};
// app/routes.js
module.exports = function(app, passport) {
app.get('/', function(req, res) {
res.render('index.ejs');
});
app.get('/profile', isLoggedIn, function(req, res) {
res.render('profile.ejs', {
user : req.user
});
});
app.get('/auth/facebook', passport.authenticate('facebook', { scope : 'email' }));
app.get('/auth/facebook/callback',
passport.authenticate('facebook', {
successRedirect : '/profile',
failureRedirect : '/'
}));
app.get('/logout', function(req, res) {
req.logout();
res.redirect('/');
});
};
function isLoggedIn(req, res, next) {
if (req.isAuthenticated())
return next();
res.redirect('/');
}
<!-- views/index.ejs -->
<!doctype html>
<html>
<head>
<title>Node Authentication</title>
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.2/css/
bootstrap.min.css"> <!-- load bootstrap css -->
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-
awesome.min.css"> <!-- load fontawesome -->
<style>
body { padding-top:80px; }
</style>
</head>
<body>
<div class="container">
<div class="jumbotron text-center">
<h1><span class="fa fa-lock"></span> Node Authentication</h1>
<p>Login or Register with:</p>
<a href="/auth/facebook" class="btn btn-primary"><span class="fa fa-facebook"></span>
Facebook</a>
</div>
</div>
</body>
</html>
<!-- views/profile.ejs -->
<!doctype html>
<html>
<head>
<title>Node Authentication</title>
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.2/css/bootstrap.min.css">
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.min.css">
<style>
body { padding-top:80px; word-wrap:break-word; }
</style>
</head>
<body>
<div class="container">
<div class="page-header text-center">
<h1><span class="fa fa-anchor"></span> Profile Page</h1>
<a href="/logout" class="btn btn-default btn-sm">Logout</a>
</div>
<div class="row">
<!-- FACEBOOK INFORMATION -->
<div class="col-sm-6">
<div class="well">
<h3 class="text-primary"><span class="fa fa-facebook"></span> Facebook</h3>
<p>
<strong>id</strong>: <%= user.facebook.id %><br>
<strong>token</strong>: <%= user.facebook.token %><br>
<strong>email</strong>: <%= user.facebook.email %><br>
<strong>name</strong>: <%= user.facebook.name %>
</p>
</div>
</div>
<html>
<head>
<title>Node Authentication</title>
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.2/css/bootstrap.min.css">
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.min.css">
<style>
body { padding-top:80px; word-wrap:break-word; }
</style>
</head>
<body>
<div class="container">
<div class="page-header text-center">
<h1><span class="fa fa-anchor"></span> Profile Page</h1>
<a href="/logout" class="btn btn-default btn-sm">Logout</a>
</div>
<div class="row">
<!-- FACEBOOK INFORMATION -->
<div class="col-sm-6">
<div class="well">
<h3 class="text-primary"><span class="fa fa-facebook"></span> Facebook</h3>
<p>
<strong>id</strong>: <%= user.facebook.id %><br>
<strong>token</strong>: <%= user.facebook.token %><br>
<strong>email</strong>: <%= user.facebook.email %><br>
<strong>name</strong>: <%= user.facebook.name %>
</p>
</div>
</div>
</div>
</div>
</body>
</html>
Exercício
Troque o método de autenticação do exercício da REST API
para aceitar a autenticação via facebook.
PROJETO
• Crie um novo projeto completo com:

• Livros, DVDs, CDs e Autor;

• Cada uma das 3 primeiras entidade possui um relacionamento com
Autor (cada uma possui um Autor);

• Crie os métodos REST para o CRUD das 4 entidades;

• Utilizar o MongoDB e autenticação com o Facebook ou Google ou
Autenticação simples;

• Os métodos GET podem ser acessados sem que o usuário esteja
autenticado;

• Os métodos POST, UPDATE e DELETE só podem ser acessados
por usuários autenticados;
https://goo.gl/npBz5q

Mais conteúdo relacionado

Mais procurados

Conceitos Básicos de OO e Java
Conceitos Básicos de OO e JavaConceitos Básicos de OO e Java
Conceitos Básicos de OO e JavaCharles Jungbeck
 
Introdução ao Android
Introdução ao AndroidIntrodução ao Android
Introdução ao AndroidJanynne Gomes
 
JavaScript - Introdução com Orientação a Objetos
JavaScript - Introdução com Orientação a ObjetosJavaScript - Introdução com Orientação a Objetos
JavaScript - Introdução com Orientação a ObjetosEduardo Mendes
 
Sistemas Distribuídos - Computação Distribuída e Paralela
Sistemas Distribuídos - Computação Distribuída e ParalelaSistemas Distribuídos - Computação Distribuída e Paralela
Sistemas Distribuídos - Computação Distribuída e ParalelaAdriano Teixeira de Souza
 
Node.js - #1 - Introdução - Rodrigo Branas
Node.js - #1 - Introdução - Rodrigo BranasNode.js - #1 - Introdução - Rodrigo Branas
Node.js - #1 - Introdução - Rodrigo BranasRodrigo Branas
 
Javascript Orientado a Objeto
Javascript Orientado a ObjetoJavascript Orientado a Objeto
Javascript Orientado a ObjetoFábio Elísio
 
Minicurso de JavaScript (Portuguese)
Minicurso de JavaScript (Portuguese)Minicurso de JavaScript (Portuguese)
Minicurso de JavaScript (Portuguese)Bruno Grange
 
01 Introdução à programação web
01 Introdução à programação web01 Introdução à programação web
01 Introdução à programação webCentro Paula Souza
 
Wireframes para sites e dispositivos móveis
Wireframes para sites e dispositivos móveisWireframes para sites e dispositivos móveis
Wireframes para sites e dispositivos móveisTersis Zonato
 
5 – Desenvolvimento de Páginas Web Dinâmicas PHP: introdução
5 – Desenvolvimento de Páginas Web Dinâmicas PHP: introdução5 – Desenvolvimento de Páginas Web Dinâmicas PHP: introdução
5 – Desenvolvimento de Páginas Web Dinâmicas PHP: introduçãoAgrupamento de Escolas da Batalha
 
Escalabilidade, Sharding, Paralelismo e Bigdata com PostgreSQL? Yes, we can!
Escalabilidade, Sharding, Paralelismo e Bigdata com PostgreSQL? Yes, we can!Escalabilidade, Sharding, Paralelismo e Bigdata com PostgreSQL? Yes, we can!
Escalabilidade, Sharding, Paralelismo e Bigdata com PostgreSQL? Yes, we can!Matheus Espanhol
 
Python - Introdução Básica
Python - Introdução BásicaPython - Introdução Básica
Python - Introdução BásicaChristian Perone
 

Mais procurados (20)

Conceitos Básicos de OO e Java
Conceitos Básicos de OO e JavaConceitos Básicos de OO e Java
Conceitos Básicos de OO e Java
 
Introdução ao Android
Introdução ao AndroidIntrodução ao Android
Introdução ao Android
 
Programação Web com HTML e CSS
Programação Web com HTML e CSSProgramação Web com HTML e CSS
Programação Web com HTML e CSS
 
JavaScript - Introdução com Orientação a Objetos
JavaScript - Introdução com Orientação a ObjetosJavaScript - Introdução com Orientação a Objetos
JavaScript - Introdução com Orientação a Objetos
 
Sistemas Distribuídos - Computação Distribuída e Paralela
Sistemas Distribuídos - Computação Distribuída e ParalelaSistemas Distribuídos - Computação Distribuída e Paralela
Sistemas Distribuídos - Computação Distribuída e Paralela
 
Node.js - #1 - Introdução - Rodrigo Branas
Node.js - #1 - Introdução - Rodrigo BranasNode.js - #1 - Introdução - Rodrigo Branas
Node.js - #1 - Introdução - Rodrigo Branas
 
Design Centrado no Usuário
Design Centrado no UsuárioDesign Centrado no Usuário
Design Centrado no Usuário
 
Javascript Orientado a Objeto
Javascript Orientado a ObjetoJavascript Orientado a Objeto
Javascript Orientado a Objeto
 
Virtualização
VirtualizaçãoVirtualização
Virtualização
 
Minicurso de JavaScript (Portuguese)
Minicurso de JavaScript (Portuguese)Minicurso de JavaScript (Portuguese)
Minicurso de JavaScript (Portuguese)
 
01 Introdução à programação web
01 Introdução à programação web01 Introdução à programação web
01 Introdução à programação web
 
Html Básico
Html BásicoHtml Básico
Html Básico
 
Node.js e Express
Node.js e ExpressNode.js e Express
Node.js e Express
 
Wireframes para sites e dispositivos móveis
Wireframes para sites e dispositivos móveisWireframes para sites e dispositivos móveis
Wireframes para sites e dispositivos móveis
 
5 – Desenvolvimento de Páginas Web Dinâmicas PHP: introdução
5 – Desenvolvimento de Páginas Web Dinâmicas PHP: introdução5 – Desenvolvimento de Páginas Web Dinâmicas PHP: introdução
5 – Desenvolvimento de Páginas Web Dinâmicas PHP: introdução
 
Java script - funções
Java script - funçõesJava script - funções
Java script - funções
 
Escalabilidade, Sharding, Paralelismo e Bigdata com PostgreSQL? Yes, we can!
Escalabilidade, Sharding, Paralelismo e Bigdata com PostgreSQL? Yes, we can!Escalabilidade, Sharding, Paralelismo e Bigdata com PostgreSQL? Yes, we can!
Escalabilidade, Sharding, Paralelismo e Bigdata com PostgreSQL? Yes, we can!
 
Python - Introdução Básica
Python - Introdução BásicaPython - Introdução Básica
Python - Introdução Básica
 
Introdução ao SQL
Introdução ao SQLIntrodução ao SQL
Introdução ao SQL
 
Aula sobre Linux.
Aula sobre Linux. Aula sobre Linux.
Aula sobre Linux.
 

Semelhante a Curso de Node JS Básico

Possibilidades com python
Possibilidades com pythonPossibilidades com python
Possibilidades com pythonUFPA
 
Node.js para desenvolvedores .NET
Node.js para desenvolvedores .NETNode.js para desenvolvedores .NET
Node.js para desenvolvedores .NETMVP Microsoft
 
Ecosistema spring a_plataforma_enterprise_jav
Ecosistema spring a_plataforma_enterprise_javEcosistema spring a_plataforma_enterprise_jav
Ecosistema spring a_plataforma_enterprise_javJulio Viegas
 
O que mudou no Ruby 1.9
O que mudou no Ruby 1.9O que mudou no Ruby 1.9
O que mudou no Ruby 1.9Nando Vieira
 
C#4 – O que há de novo
C#4 – O que há de novoC#4 – O que há de novo
C#4 – O que há de novoGiovanni Bassi
 
Simpósio Unicruz: OpenCV + Python (parte 1)
Simpósio Unicruz: OpenCV + Python (parte 1)Simpósio Unicruz: OpenCV + Python (parte 1)
Simpósio Unicruz: OpenCV + Python (parte 1)Cristiano Rafael Steffens
 
Python, a arma secreta do Google
Python, a arma secreta do GooglePython, a arma secreta do Google
Python, a arma secreta do GoogleLuciano Ramalho
 
Inovações Na Plataforma Java
Inovações Na Plataforma JavaInovações Na Plataforma Java
Inovações Na Plataforma JavaFilipe Portes
 
Vetorização e Otimização de Código - Intel Software Conference 2013
Vetorização e Otimização de Código - Intel Software Conference 2013Vetorização e Otimização de Código - Intel Software Conference 2013
Vetorização e Otimização de Código - Intel Software Conference 2013Intel Software Brasil
 
TDC2016SP - Trilha Node.Js
TDC2016SP - Trilha Node.JsTDC2016SP - Trilha Node.Js
TDC2016SP - Trilha Node.Jstdc-globalcode
 
Desenvolvimento Agil Com Doctrine Orm
Desenvolvimento Agil Com Doctrine OrmDesenvolvimento Agil Com Doctrine Orm
Desenvolvimento Agil Com Doctrine OrmGuilherme Blanco
 
TDC 2014 SP - E o DeltaSpike ?
TDC 2014 SP - E o DeltaSpike ?TDC 2014 SP - E o DeltaSpike ?
TDC 2014 SP - E o DeltaSpike ?Rafael Benevides
 

Semelhante a Curso de Node JS Básico (20)

Possibilidades com python
Possibilidades com pythonPossibilidades com python
Possibilidades com python
 
Node.js para desenvolvedores .NET
Node.js para desenvolvedores .NETNode.js para desenvolvedores .NET
Node.js para desenvolvedores .NET
 
Comecando tensorflow
Comecando tensorflowComecando tensorflow
Comecando tensorflow
 
Node JS - Parte 1
Node JS - Parte 1Node JS - Parte 1
Node JS - Parte 1
 
Ecosistema spring a_plataforma_enterprise_jav
Ecosistema spring a_plataforma_enterprise_javEcosistema spring a_plataforma_enterprise_jav
Ecosistema spring a_plataforma_enterprise_jav
 
O que mudou no Ruby 1.9
O que mudou no Ruby 1.9O que mudou no Ruby 1.9
O que mudou no Ruby 1.9
 
Desenvolvimento iOS
Desenvolvimento iOSDesenvolvimento iOS
Desenvolvimento iOS
 
C#4 – O que há de novo
C#4 – O que há de novoC#4 – O que há de novo
C#4 – O que há de novo
 
Simpósio Unicruz: OpenCV + Python (parte 1)
Simpósio Unicruz: OpenCV + Python (parte 1)Simpósio Unicruz: OpenCV + Python (parte 1)
Simpósio Unicruz: OpenCV + Python (parte 1)
 
Palestra cbq
Palestra cbqPalestra cbq
Palestra cbq
 
Python, a arma secreta do Google
Python, a arma secreta do GooglePython, a arma secreta do Google
Python, a arma secreta do Google
 
Inovações Na Plataforma Java
Inovações Na Plataforma JavaInovações Na Plataforma Java
Inovações Na Plataforma Java
 
Vetorização e Otimização de Código - Intel Software Conference 2013
Vetorização e Otimização de Código - Intel Software Conference 2013Vetorização e Otimização de Código - Intel Software Conference 2013
Vetorização e Otimização de Código - Intel Software Conference 2013
 
Palestra2009
Palestra2009Palestra2009
Palestra2009
 
Python e MongoDB - Ensol
Python e MongoDB - EnsolPython e MongoDB - Ensol
Python e MongoDB - Ensol
 
TDC2016SP - Trilha Node.Js
TDC2016SP - Trilha Node.JsTDC2016SP - Trilha Node.Js
TDC2016SP - Trilha Node.Js
 
Introdução Ruby 1.8.7 + Rails 3
Introdução Ruby 1.8.7 + Rails 3Introdução Ruby 1.8.7 + Rails 3
Introdução Ruby 1.8.7 + Rails 3
 
Oficial
OficialOficial
Oficial
 
Desenvolvimento Agil Com Doctrine Orm
Desenvolvimento Agil Com Doctrine OrmDesenvolvimento Agil Com Doctrine Orm
Desenvolvimento Agil Com Doctrine Orm
 
TDC 2014 SP - E o DeltaSpike ?
TDC 2014 SP - E o DeltaSpike ?TDC 2014 SP - E o DeltaSpike ?
TDC 2014 SP - E o DeltaSpike ?
 

Mais de Victor Hazin da Rocha

Aula de Sistemas Distribuídos - Padrões de Projeto de Middleware
Aula de Sistemas Distribuídos - Padrões de Projeto de MiddlewareAula de Sistemas Distribuídos - Padrões de Projeto de Middleware
Aula de Sistemas Distribuídos - Padrões de Projeto de MiddlewareVictor Hazin da Rocha
 
Aula de Sistemas Distribuídos - Tolerância a Falhas
Aula de Sistemas Distribuídos - Tolerância a FalhasAula de Sistemas Distribuídos - Tolerância a Falhas
Aula de Sistemas Distribuídos - Tolerância a FalhasVictor Hazin da Rocha
 
Aula de Sistemas Distribuídos - Invocação Remota
Aula de Sistemas Distribuídos - Invocação RemotaAula de Sistemas Distribuídos - Invocação Remota
Aula de Sistemas Distribuídos - Invocação RemotaVictor Hazin da Rocha
 
Introdução a Sistemas Distribuídos
Introdução a Sistemas DistribuídosIntrodução a Sistemas Distribuídos
Introdução a Sistemas DistribuídosVictor Hazin da Rocha
 
Aula de Sistemas Distribuídos - Comunicação Indireta
Aula de Sistemas Distribuídos - Comunicação IndiretaAula de Sistemas Distribuídos - Comunicação Indireta
Aula de Sistemas Distribuídos - Comunicação IndiretaVictor Hazin da Rocha
 
Teoria dos Grafos - História e COnceitos Iniciais
Teoria dos Grafos - História e COnceitos IniciaisTeoria dos Grafos - História e COnceitos Iniciais
Teoria dos Grafos - História e COnceitos IniciaisVictor Hazin da Rocha
 

Mais de Victor Hazin da Rocha (6)

Aula de Sistemas Distribuídos - Padrões de Projeto de Middleware
Aula de Sistemas Distribuídos - Padrões de Projeto de MiddlewareAula de Sistemas Distribuídos - Padrões de Projeto de Middleware
Aula de Sistemas Distribuídos - Padrões de Projeto de Middleware
 
Aula de Sistemas Distribuídos - Tolerância a Falhas
Aula de Sistemas Distribuídos - Tolerância a FalhasAula de Sistemas Distribuídos - Tolerância a Falhas
Aula de Sistemas Distribuídos - Tolerância a Falhas
 
Aula de Sistemas Distribuídos - Invocação Remota
Aula de Sistemas Distribuídos - Invocação RemotaAula de Sistemas Distribuídos - Invocação Remota
Aula de Sistemas Distribuídos - Invocação Remota
 
Introdução a Sistemas Distribuídos
Introdução a Sistemas DistribuídosIntrodução a Sistemas Distribuídos
Introdução a Sistemas Distribuídos
 
Aula de Sistemas Distribuídos - Comunicação Indireta
Aula de Sistemas Distribuídos - Comunicação IndiretaAula de Sistemas Distribuídos - Comunicação Indireta
Aula de Sistemas Distribuídos - Comunicação Indireta
 
Teoria dos Grafos - História e COnceitos Iniciais
Teoria dos Grafos - História e COnceitos IniciaisTeoria dos Grafos - História e COnceitos Iniciais
Teoria dos Grafos - História e COnceitos Iniciais
 

Curso de Node JS Básico

  • 2. Victor Hazin Engenheiro de Software do CESAR (+ 7 anos) Professor da FBV Devry (+3 anos) Graduação e Mestrado em Ciências da Computação (CIn-UFPE) (2010 e 1013)
  • 4. Presentation layer Business Logic layer Data Access layer Full Stack Web Development
  • 5. Presentation layer Business Logic layer Data Access layer Front-end Back-end
  • 6. Presentation layer Business Logic layer Data Access layer NodeJS and NodeJS Modules Single page Apps using Javascript Frameworks (AngularJS) MongoDB JSON documents REST API
 serving JSON
  • 7. Presentation layer Business Logic layer Data Access layer NodeJS Modules NodeJS BaaS MongoDB UI Framework Bootstrap JS Framework Angular JS JS CSS HTML
  • 8. Presentation layer Business Logic layer Data Access layer NodeJS Modules NodeJS BaaS MongoDB UI Framework Bootstrap JS Framework Angular JS JS CSS HTML Back-end
  • 12. “é uma plataforma para aplicações JavaScript criada por Ryan Dahl sob o ambiente de execução JavaScript do Chrome. É possível utilizar bibliotecas desenvolvidas pela comunidade através de seu gerenciador de pacotes chamado npm”
  • 19. Configurando o ambiente de desenvolvimento Adicionar uma variável de ambiente NODE_ENV no sistema operacional. Linux ou OSX: 1. acessar com um editor de texto qualquer e em modo super user (sudo) o arquivo .bash_profile ou .bashrc 2. adicionar o seguinte comando: export NODE_ENV=’development No Windows: 1. Clique com botão direito no ícone Meu Computador e selecione a opção Propriedades 2. Clique em Configurações avançadas do sistema. 3. Na janela seguinte, acesse a aba Avançado e clique no botão Variáveis de Ambiente. 4. No campo Variáveis do sistema clique no botão Novo. 5. Em nome da variável digite NODE_ENV e em valor da variável digite: development.
  • 20. $ node > console.log('Hello World') Hello World undefined >
  • 22. npm • Gerenciador de pacotes do node.js; • Similar ao Maven do Java ou ao Gems do Ruby; • Foi integrado ao instalador do Node.js a partir da versão 0.6.
  • 23. npm install nome_do_módulo: instala um módulo no projeto; npm install -g nome_do_módulo: instala um módulo global; npm install nome_do_módulo --save: instala o módulo no projeto, atualizando o package.json na lista de dependências; npm list: lista todos os módulos do projeto; npm list -g: lista todos os módulos globais; Comandos Principais (npm)
  • 24. npm remove nome_do_módulo: desinstala um módulo do projeto; npm remove -g nome_do_módulo: desinstala um módulo global; npm update nome_do_módulo: atualiza a versão do módulo; npm update -g nome_do_módulo: atualiza a versão do módulo global; Comandos Principais (npm)
  • 25. Comandos Principais (npm) npm -v: exibe a versão atual do npm; npm adduser nome_do_usuário: cria uma conta no npm, através do site https://npmjs.org. npm whoami: exibe detalhes do seu per l público npm (é necessário criar uma conta antes); npm publish: publica um módulo no site do npm (é necessário ter uma conta antes).
  • 28. node modules Todo projeto Node.js é chamado de módulo; O termo módulo, biblioteca e framework possuem o mesmo significado (na prática); O termo módulo surgiu do conceito de que a arquitetura do Node.js é modular; Todo módulo é acompanhado de um arquivo descritor (package.json).
  • 29. package.json { "name": "winter-is-coming—node-app", "description": "Meu primeiro app na Muralha", "author": "Jon Snow <jonsnow@norte.com>", "version": "1.2.3", "private": true, "dependencies": { "modulo-1": "1.0.0", "modulo-2": "~1.0.0", "modulo-3": ">=1.0.0" }, "devDependencies": { "modulo-4": "*" } }
  • 31. CommonJS • O Node.js utiliza nativamente o padrão CommonJS para organização e carregamento de módulos; • Para criar um código Javascript que seja modular e carregável pelo require, utilizam-se as variáveis globais: exports ou module.exports.
  • 32. hello.js human.js Em hello.js carregamos uma única função modular; Em human.js é carregado um objeto com funções modulares. app.js module.exports = function(msg) { console.log(msg); }; exports.hello = function(msg) { console.log(msg); }; var hello = require(’./hello’); var human = require(’./human’); hello(’Olá pessoal!’); human.hello(’Olá galera!’);
  • 34. 1. Crie uma pasta com o nome: node-exemplos 2. Crie um arquivo com o nome retangulo.js 3. Execute execute a aplicação com o comando: node retangulo.js var rect = { perimeter: function (x, y) { return (2*(x+y)); }, area: function (x, y) { return (x*y); } }; function solveRect(l,b) { console.log("Solving for rectangle with l = " + l + " and b = " + b); if (l < 0 || b < 0) { console.log("Rectangle dimensions should be greater than zero: l = " + l + ", and b = " + b); } else { console.log("The area of a rectangle of dimensions length = " + l + " and breadth = " + b + " is " + rect.area(l,b)); console.log("The perimeter of a rectangle of dimensions length = " + l + " and breadth = " + b + " is " + rect.perimeter(l,b)); } } solveRect(2,4); solveRect(3,5); solveRect(-3,5);
  • 35. 1. Crie um novo arquivo com o nome retangulo-1.js exports.perimeter = function (x, y) { return (2*(x+y)); } exports.area = function (x, y) { return (x*y); } 2. Crie um novo arquivo com o nome solucao-1.js var rect = require('./retangulo-1'); function solveRect(l,b) { console.log("Solving for rectangle with l = " + l + " and b = " + b); if (l < 0 || b < 0) { console.log("Rectangle dimensions should be greater than zero: l = " + l + ", and b = " + b); } else { console.log("The area of a rectangle of dimensions length = " + l + " and breadth = " + b + " is " + rect.area(l,b)); console.log("The perimeter of a rectangle of dimensions length = " + l + " and breadth = " + b + " is " + rect.perimeter(l,b)); } } solveRect(2,4); solveRect(3,5); solveRect(-3,5); 3. Execute execute a aplicação com o comando: node solucao-1
  • 36. Callbacks e Tratamento de Erros node modules
  • 37. JavaScript e funções como parâmetro function falar(palavra) { console.log(palavra); } function executar(funcao, valor) { funcao(valor); } executar(falar, "Oi JavaScript!”); $ node > function falar(palavra){ ... console.log(palavra); ... } undefined > function executar(funcao, valor){ ... funcao(valor); ... } undefined > executar(falar, "Oi JavaScript!"); Oi JavaScript! undefined >
  • 38. Processo 3 Processo 2 I/O (Processo Lento) Processo 1 Processo 3 Callback I/O (Processo Lento) Processo 1 AssíncronoSíncrono
  • 41. module.exports = function(x,y,callback) { try { if (x < 0 || y < 0) { throw new Error("Rectangle dimensions should be greater than zero: l = " + x + ", and b = " + y); } else callback(null, { perimeter: function () { return (2*(x+y)); }, area:function () { return (x*y); } }); } catch (error) { callback(error,null); } } 1. Crie um arquivo com o nome retangulo-2.js
  • 42. var rect = { perimeter: function () { return (2*(x+y)); }, area:function () { return (x*y); } module.exports = function(x,y,callback) { try { if (x < 0 || y < 0) { throw new Error("Rectangle dimensions should be greater than zero: l = " + x + ", and b = " + y); } else callback(null, rect); } catch (error) { callback(error,null); } } 1. Crie um arquivo com o nome retangulo-2.js
  • 43. var rect = require('./retangulo-2'); function solveRect(l,b) { console.log("Solving for rectangle with l = " + l + " and b = " + b); rect(l,b, function(err,rectangle) { if (err) { console.log(err); } else { console.log("The area of a rectangle of dimensions length = " + l + " and breadth = " + b + " is " + rectangle.area()); console.log("The perimeter of a rectangle of dimensions length = " + l + " and breadth = " + b + " is " + rectangle.perimeter()); } }); }; solveRect(2,4); solveRect(3,5); solveRect(-3,5); 2. Crie um novo arquivo com o nome solucao-2.js 3. Execute execute a aplicação com o comando: node solucao-2
  • 44. var argv = require('yargs') .usage('Usage: node $0 --l=[num] --b=[num]') .demand(['l','b']) .argv; var rect = require('./retangulo-2'); function solveRect(l,b) { console.log("Solving for rectangle with l = " + l + " and b = " + b); rect(l,b, function(err,rectangle) { if (err) { console.log(err); } else { console.log("The area of a rectangle of dimensions length = " + l + " and breadth = " + b + " is " + rectangle.area()); console.log("The perimeter of a rectangle of dimensions length = " + l + " and breadth = " + b + " is " + rectangle.perimeter()); } }); }; solveRect(argv.l,argv.b); 1. Crie um novo arquivo com o nome solucao-3.js 3. Execute execute a aplicação com o comando: node solucao-3 --l=5 --b=6 2. Instale o yargs com o comando: npm install yargs --save
  • 45. node e http Desenvolvendo aplicações web
  • 46. Node.js é multi-protocolo: HTTP, HTTPS, FTP, SSH, DNS, TCP, UDP, WebSockets; Toda aplicação web necessita de um servidor para disponibilizar todos os seus recursos; Na prática, com o Node.js você desenvolve uma aplicação middleware; Além de programar as funcionalidades da sua aplicação, você também programa códigos de configuração de infraestrutura da sua aplicação.
  • 47. Alguns módulos conhecidos são: • Connect (https://github.com/senchalabs/connect); • Express (http://expressjs.com); • Geddy (http://geddyjs.org); • CompoundJS (http://compoundjs.com); • Sails (http://balderdashy.github.io/sails);
  • 48. Esses módulos já são preparados para lidar com desde uma infraestrutura mínima até uma mais enxuta; E permitem trabalhar com diferentes arquiteturas e padrões. • RESTFul; • Padrão MVC; • Model-View-Controller • e conexões real-time utilizando WebSocket;
  • 49. var http = require('http'); var server = http.createServer(function(request, response){ response.writeHead(200, {"Content-Type": "text/html"}); response.write("<h1>Hello World!</h1>"); response.end(); }); server.listen(3000); 1. Crie um novo arquivo com o nome hello_server.js 2. Execute execute a aplicação com o comando: node hello_server.js 3. No seu navegador acesse o endereço http://localhost:3000
  • 50. var http = require('http'); var server = http.createServer(function(request, response){ response.writeHead(200, {"Content-Type": "text/html"}); response.write("<h1>Hello World!</h1>"); response.end(); }); server.listen(3000); O require(‘http') carrega o módulo http padrão do node
  • 51. var http = require('http'); var server = http.createServer(function(request, response){ response.writeHead(200, {"Content-Type": "text/html"}); response.write("<h1>Hello World!</h1>"); response.end(); }); server.listen(3000); A função http.createServer() é responsável por levantar um servidor; O callback function(request, response) só é executada quando o servidor recebe uma requisição. Event loop constantemente verifica se o servidor foi requisitado; Quando uma requisição é recebida, é emitido um evento para que seja executado o callback.
  • 52. var http = require('http'); var server = http.createServer(function(request, response){ response.writeHead(200, {"Content-Type": "text/html"}); response.write("<h1>Hello World!</h1>"); response.end(); }); server.listen(3000, function(){ console.log(’Servidor Hello World rodando!’); }); Notificar quando servidor está de pé, mudamos a linha server.listen para receber como parâmetro uma função que faz esse aviso.
  • 53. var http = require('http'); var server = http.createServer(function(request, response){ response.writeHead(200, {"Content-Type": "text/html"}); response.write("<h1>Hello World!</h1>"); response.end(); }); server.listen(3000); Os parâmetros da requisição http podem ser obtidos através da variável request: • request.headers; • request.body; Já os dados do cabeçalho HTML podem ser atribuídos usando o parâmetro response: • response.writeHead(200, {"Content-Type": “text/html"}); • response.write("<h1>Hello World!</h1>");
  • 54. Trabalhando com Rotas var http = require(’http’); var server = http.createServer(function(request, response){ response.writeHead(200, {"Content-Type": "text/html"}); if(request.url == "/"){ response.write("<h1>Página principal</h1>"); }else if(request.url == "/bemvindo"){ response.write("<h1>Bem-vindo :)</h1>"); }else{ response.write("<h1>Página não encontrada :(</h1>"); } response.end(); }); server.listen(3000, function(){ console.log(’Servidor rodando!’); });
  • 55. Separando o HTML do JavaScript var http = require('http'); var fs = require('fs'); var server = http.createServer(function(request, response){ fs.readFile(__dirname + '/index.html', function(erro, html){ response.writeHeader(200, {'Content-Type': 'text/html'}); response.write(html); response.end(); }); }); server.listen(3000, function(){ console.log('Servidor Rodando…'); }); <!DOCTYPE html> <html> <head> <title>The winter is coming!</title> </head> <body> <h1>Bem vindo ao Norte!</h1> </body> </html> index.html exercicio_html_javascript.js
  • 57. Implementar um Roteador de URLs • Crie 3 arquivos HTML simples: inverno.html, verao.html e erro.html; • Coloque qualquer conteúdo para cada página HTML; • Ao digitar no browser o path: /inverno deve renderizar inverno.html; • Ao digitar no browser o path: /verao deve renderizar verao.html; • Ao digitar qualquer path diferente de /verao e /inverno deve renderizar erro.html; • A leitura dos arquivos HTML deve ser assíncrona; • A rota principal "/" deve renderizar inverno.html;
  • 58. Fast, unopinionated, minimalist web framework for Node.js express
  • 59. É um framework web light-weight criado em 2009 que ajuda na organização de sua aplicação web, na arquitetura MVC no lado do servidor; express
  • 60. O Express é uma estrutura web de roteamento e middlewares que tem uma funcionalidade mínima por si só; Um aplicativo do Express é essencialmente uma série de chamadas de funções de middleware. express
  • 61. Funções de Middleware são funções que tem acesso: • Ao objeto de solicitação (req); • O objeto de resposta (res); • E a próxima função de middleware no ciclo solicitação-resposta do aplicativo (next). express
  • 62. O método HTTP para o qual a função de middleware é aplicada. Caminho (rota) para o qual a função de middleware é aplicada. A função de middleware. Argumento de retorno de chamada para a função de middleware, chamado de "next" por convenção. Argumento de resposta HTTP para a função de middleware, chamado de "res" por convenção. Argumento de solicitação HTTP para a função de middleware, chamado de "req" por convenção express
  • 63. O método HTTP para o qual a função de middleware é aplicada. Caminho (rota) para o qual a função de middleware é aplicada. A função de middleware. Argumento de retorno de chamada para a função de middleware, chamado de "next" por convenção. Argumento de resposta HTTP para a função de middleware, chamado de "res" por convenção. Argumento de solicitação HTTP para a função de middleware, chamado de "req" por convenção express
  • 64. O método HTTP para o qual a função de middleware é aplicada. Caminho (rota) para o qual a função de middleware é aplicada. A função de middleware. Argumento de retorno de chamada para a função de middleware, chamado de "next" por convenção. Argumento de resposta HTTP para a função de middleware, chamado de "res" por convenção. Argumento de solicitação HTTP para a função de middleware, chamado de "req" por convenção express
  • 65. O método HTTP para o qual a função de middleware é aplicada. Caminho (rota) para o qual a função de middleware é aplicada. A função de middleware. Argumento de retorno de chamada para a função de middleware, chamado de "next" por convenção. Argumento de resposta HTTP para a função de middleware, chamado de "res" por convenção. Argumento de solicitação HTTP para a função de middleware, chamado de "req" por convenção express
  • 66. O método HTTP para o qual a função de middleware é aplicada. Caminho (rota) para o qual a função de middleware é aplicada. A função de middleware. Argumento de retorno de chamada para a função de middleware, chamado de "next" por convenção. Argumento de resposta HTTP para a função de middleware, chamado de "res" por convenção. Argumento de solicitação HTTP para a função de middleware, chamado de "req" por convenção express
  • 67. O método HTTP para o qual a função de middleware é aplicada. Caminho (rota) para o qual a função de middleware é aplicada. A função de middleware. Argumento de retorno de chamada para a função de middleware, chamado de "next" por convenção. Argumento de resposta HTTP para a função de middleware, chamado de "res" por convenção. Argumento de solicitação HTTP para a função de middleware, chamado de "req" por convenção express
  • 68. O método HTTP para o qual a função de middleware é aplicada. Caminho (rota) para o qual a função de middleware é aplicada. A função de middleware. Argumento de retorno de chamada para a função de middleware, chamado de "next" por convenção. Argumento de resposta HTTP para a função de middleware, chamado de "res" por convenção. Argumento de solicitação HTTP para a função de middleware, chamado de "req" por convenção express
  • 69. Funções de middleware podem executar as seguintes tarefas: • Executar qualquer código; • Fazer mudanças nos objetos de solicitação e resposta; • Encerrar o ciclo de solicitação-resposta; • Chamar a próxima função de middleware na pilha; • Se a atual função de middleware não terminar o ciclo de solicitação-resposta, ela precisa chamar next(). express
  • 70. Crie uma pasta para colocar o novo exemplo; Em seguida no terminal/linha de comando navegue até a pasta e instale o express: express $ npm install express --save
  • 71. Express Hello World var express = require('express'), http = require('http'); var hostname = 'localhost'; var port = 3000; var app = express(); app.use(function (req, res, next) { res.writeHead(200, { 'Content-Type': 'text/html' }); res.end('<html><body><h1>Hello World</h1></body></html>'); }); var server = http.createServer(app); server.listen(port, hostname, function(){ console.log(`Server running at http://${hostname}:${port}/`); }); express $ node intro-express.js Crie um arquivo chamado intro-express.js
  • 72. Para entregar arquivos estáticos como imagens, arquivos CSS, e arquivos JavaScript, use a função de middleware express.static; Passe o nome do diretório que contém os ativos estáticos para a função de middleware express.static para iniciar a entregar os arquivos diretamente; Por exemplo, use o código a seguir para entregar imagens, arquivos CSS, e arquivos JavaScript em um diretório chamado public. express
  • 73. Agora, é possível carregar os arquivos que estão no diretório public: express app.use(express.static('public')); http://localhost:3000/images/kitten.jpg http://localhost:3000/css/style.css http://localhost:3000/js/app.js http://localhost:3000/images/bg.png http://localhost:3000/hello.html
  • 74. Serving Static Content Crie uma pasta chamada public e coloque dentro dois arquivos html quaisquer; var express = require('express'); var hostname = 'localhost'; var port = 3000; var app = express(); app.use(express.static(__dirname + '/public')); app.listen(port, hostname, function(){ console.log(`Server running at http://${hostname}:${port}/`); }); express
  • 76. Representational State Transfer (REST) or RESTful web services é uma maneira simples de organizar interações em sistemas independentes. Proporcionando interoperabilidade entre o sistema e os diversos dispositivos com acesso a Internet.
  • 77. Os serviços da Web compatíveis com REST permitem que os sistemas solicitantes acessem e manipulem representações textuais de recursos da Web usando um conjunto uniforme e predefinido de operações stateless.
  • 78. Os princípios fundamentais do REST envolvem separar sua API em recursos lógicos. Esses recursos são manipulados usando solicitações HTTP nas quais o método (GET, POST, PUT, PATCH ou DELETE) tem um significado específico. Recursos devem ser substantivos (não verbos!) que fazem sentido do ponto de vista do quem vai “consumir” a AP
  • 79. Depois da definição dos recursos, é necessário identificar quais ações se aplicam a eles e como serão mapeados para a API. Princípios RESTful fornecem estratégias para lidar com ações CRUD usando métodos HTTP mapeados, tal como: • GET /tickets Retorna a lista de bilhetes • GET /tickets/12 Retorna um bilhete específico • POST /tickets Cria um novo bilhete • PUT /tickets/12 Atualiza o bilhete #12 • PATCH /tickets/12 Atualiza parcialmente o bilhete #12 • DELETE /tickets/12 Apaga o bilhete #12
  • 80. A grande vantagem em REST é que se está aproveitando métodos HTTP existentes para implementar funcionalidades significativas em apenas um único endpoint /tickets; Não existem convenções de nomenclatura a seguir e a estrutura de URL é limpa e clara. RESPOSTAS SEMPRE EM JSON!!!!
  • 83. O Roteamento refere-se à determinação de como um aplicativo responde a uma solicitação do cliente por um endpoint específico; A solicitação é compostas por uma URI (ou caminho) e um método de solicitação HTTP específico (GET, POST, e assim por diante); Cada rota pode ter uma ou mais funções de manipulação, que são executadas quando a rota é correspondida.
  • 84. A definição de rotas aceita a seguinte estrutura: Onde: app é uma instância do express; METHOD é um método de solicitação HTTP; PATH é um caminho no servidor; HANDLER é a função executada quando a rota é correspondida. app.METHOD(PATH, HANDLER)
  • 85. app.get('/', function (req, res) { res.send('Hello World!'); }); Responde uma requisição GET com Hello World! na página inicial.
  • 86. app.post('/', function (req, res) { res.send('Got a POST request'); }); Responder a uma solicitação POST na rota raiz (/) com a página inicial do aplicativo.
  • 87. app.put('/user', function (req, res) { res.send('Got a PUT request at /user'); }); Responder a uma solicitação PUT para a rota 
 /user.
  • 88. app.delete('/user', function (req, res) { res.send('Got a DELETE request at /user'); }); Responder a uma solicitação DELETE para a rota /user.
  • 91. var express = require('express'); var morgan = require('morgan'); var bodyParser = require('body-parser'); var hostname = 'localhost'; var port = 3000; var app = express(); app.use(morgan('dev')); app.use(bodyParser.json()); app.all('/books', function(req,res,next) { res.writeHead(200, { 'Content-Type': 'text/plain' }); next(); }); app.get('/books', function(req,res,next){ res.end('Will send all the books to you!'); }); app.get('/books/:bookId', function(req,res,next){ res.end('Will send details of the book: ' + req.params.bookId +' to you!'); }); . . . app.listen(port, hostname, function(){ console.log(`Server running at http://${hostname}:${port}/`); });
  • 93. Use a classe express.Router para criar manipuladores de rota modulares e montáveis. Uma instância de Router é um middleware e sistema de roteamento completo; Por essa razão, é frequentemente tratado como um “mini- aplicativo”
  • 94. var express = require('express'); var router = express.Router(); router.use(function timeLog(req, res, next) { console.log('Time: ', Date.now()); next(); }); router.get('/', function(req, res) { res.send('Winter is Comming Home page'); }); router.get('/about', function(req, res) { res.send('Tratar com Jon Snow'); }); module.exports = router; Crie um arquivo de roteador com um arquivo chamado winter.js no diretório do aplicativo, com o seguinte conteúdo:
  • 95. var express = require('express'); var hostname = 'localhost'; var port = 3000; var app = express(); var winter = require('./winter'); app.use('/winters', winter); app.listen(port, hostname, function(){ console.log(`Server running at http://${hostname}:${port}/`); }); Crie um arquivo de roteador com um arquivo chamado winter-server.js no diretório do aplicativo, com o seguinte conteúdo:
  • 97. Agora atualize seu código para utilizar o express.Router e implemente as seguintes rotas:
  • 99. Express Generator Usado criar rapidamente uma estrutura básica de projeto; Instale o express generator com o comando a seguir: $ npm install express-generator -g
  • 100. $ express --view=pug things-app create : things-app create : things-app/package.json create : things-app/app.js create : things-app/public create : things-app/public/javascripts create : things-app/public/images create : things-app/routes create : things-app/routes/index.js create : things-app/routes/users.js create : things-app/public/stylesheets create : things-app/public/stylesheets/style.css create : things-app/views create : things-app/views/index.pug create : things-app/views/layout.pug create : things-app/views/error.pug create : things-app/bin create : things-app/bin/www
  • 101. !"" app.js !"" bin # $"" www !"" package.json !"" public # !"" images # !"" javascripts # $"" stylesheets # $"" style.css !"" routes # !"" index.js # $"" users.js $"" views !"" error.pug !"" index.pug $"" layout.pug 7 directories, 9 files O aplicativo gerado possui a seguinte estrutura de diretórios: app.js: starting application package.json public: static resources routes: application routes views: template engine templates
  • 103. Nesta tarefa você continuará a exploração de módulos Node, Express e API REST. Você deve: Criar um módulo usando o Express Router para suportar as rotas para os waters REST API. Criar um módulo usando o Express Router para suportar as rotas para os temperatures REST API. Criar um módulo usando o Express Router para suportar as rotas para os energy REST API. http://localhost:3000/waters http://localhost:3000/temperatures http://localhost:3000/energy É necessário suportar as operações GET, PUT, POST e DELETE em cada um dos três endpoints, incluindo o suporte ao uso de parâmetros de rota para identificar um registro específico.
  • 106. Cada paradigma apresentado ataca problemas diferentes e sua escolha não é uma decisão puramente preferencial, mas de necessidade do projeto, tangendo aspectos arquiteturais e mais abstratos
  • 110. O MongoDB é um banco de dados baseado em documento com alta performance e disponibilidade e de fácil escalabilidade
  • 111. Document: informação completa e “autocontida”; JSON document:
 {“name”: “Uthapizza”, 
 ”description”: “A unique combination . . .”} Collection: coleção de documentos; Database: conjunto de coleções. database
  • 112. O conceito de documento Um documento pode ser armazenado em diferentes formatos hierárquicos como XML ou JSON com os dados associados a uma estrutura de chave e valor. É através de uma chave específica do documento que temos acesso ao valor associado.
  • 113. O conceito de documento O MongoDB armazena seus documentos no formato BSON (Binary JSON), muito parecido com JSON. Comparemos a estrutura desses dois formatos: // JSON { "nome" : "Jon Snow" } // BSON { "_id" : ObjectId("5303e0649fd1396") "nome" : "Jon Snow" }
  • 114. Diferença entre BSON e JSON É a quantidade dos tipos de dados suportados em cada uma deles: JSON: 6 tipos (Array, Boolean, null, Number, Object e String) BSON: +15 tipos
  • 115. Tipos de Dados (BSON)
  • 116. ObjectId Todo documento criado recebe automaticamente a chave _id contendo como valor padrão um objeto do tipo ObjectId. • São pequenos; • Provavelmente únicos; • Rápidos para gerar e ordenados; • Consistem de 12 bytes; • Os 4 primeiros são um timestamp que reflete o momento da criação.
  • 117. Instalação https://docs.mongodb.com/manual/installation/ É altamente recomendável utilizar a versão de 64 Bits em produção pelo fato de o banco na versão de 32 Bits ser limitado a um tamanho de no máximo dois gigabytes.
  • 119. Criando e Rodando o Banco Uma forma testar a instalação do MongoDB é coma cliente de linha de comando: o mongo shell Abra uma nova janela do terminal (sem fechar) e execute o seguinte comando: $ mongod --dbpath <path> $ mongo
  • 121. Criando uma nova base de dados No terminal executando o “mongo shell” rode o comando: Em execute o comando db para verificar qual base de dados está sendo usada > db things > use things
  • 122. Criando uma nova coleção No terminal executando o “mongo shell” rode o comando: Se uma coleção não existe, o MongoDB cria a coleção quando ele salva os dados pela primeira vez. > db.myNewCollection.insertOne( { x: 1 } ) > db.myNewCollection2.createIndex( { y: 1 } )
  • 123. MongoDB CRUD (Create) MongoDB fornece os seguintes métodos para inserir documentos em uma coleção: db.collection.insertOne() 
 db.collection.insertMany()
  • 124. MongoDB CRUD (Read) Operações de leitura recuperam documentos de uma coleção;
  • 125. MongoDB CRUD (Update) MongoDB fornece os seguintes métodos para atualizar documentos de uma coleção: db.collection.updateOne() 
 db.collection.updateMany()
 db.collection.replaceOne()
  • 126. MongoDB CRUD (Delete) O MongoDB fornece os seguintes métodos para excluir documentos de uma coleção: db.collection.deleteOne() 
 db.collection.deleteMany()
  • 128. É preciso que a aplicação seja capaz de se conectar e realizar operações no banco de dados; Para isso MongoDB possui um driver nativo, criado especialmente para o Node.js; Sua instalação é feita através do npm como qualquer outro módulo do Node.js: https://github.com/mongodb/node-mongodb-native npm install mongodb --save
  • 129. Conectando ao mongoDB var MongoClient = require('mongodb').MongoClient , co = require('co') , assert = require('assert'); // 1. Connect to MongoDB instance running on localhost // Connection URL var url = 'mongodb://localhost:27017/test'; co(function*() { const db = yield MongoClient.connect(url); console.log("Connected successfully to server"); yield insertDocuments(db, null); yield findDocuments(db, null); yield indexCollection(db, null); yield aggregateDocuments(db, null); db.close(); }).catch(err => console.log(err));
  • 130. Inserindo no Banco var insertDocuments = function(db, callback) { return co(function*() { const results = yield db.collection('restaurants') .insertMany( [ {“name":"Sun Trattoria", "stars":4, "categories":["Pizza","Pasta","Italian","Coffee"]}, {"name":"Blue Bagels Grill", "stars":3, "categories":["Bagels","Cookies","Sandwiches"]}, {"name":"Hot Bakery Cafe","stars":4,"categories":["Bakery","Cafe","Coffee","Dessert"]}, {"name":"XYZ Coffee Bar","stars":5,"categories":["Coffee","Cafe","Bakery","Chocolates"]}, {"name":"456 Cookies Shop","stars":4,"categories":["Bakery","Cookies","Cake","Coffee"]} ]); console.log(results) return results; }); }
  • 131. Fazendo uma Busca no Banco var findDocuments = function(db) { return co(function*() { // Get the documents collection const collection = db.collection('restaurants'); const docs = yield collection.find({}).toArray(); console.log("Found the following records"); console.log(docs) return docs; }); }
  • 133. Exercício Crie uma nova base de dados para o seu projeto; A base deve conter no mínimo 5 coleções; cada coleção deve representar o conjunto de informações gerados por um sensor diferente (ex: sensor que monitora a água da casa, a energia…); Popule as coleções com dados “fake"; Faça consultas para extrair informações importantes da base de dados.
  • 134. Exercício Crie um novo módulo (chamado operations.js) para o Node contendo algumas operações comuns de MongoDB (CRUD); Use o módulo na sua aplicação e comunique-se com o servidor MongoDB (o módulo deve ser reaproveitável para ser utilizado por qualquer novo “tipo” que for criado). var assert = require('assert'); exports.insertDocument = function(db, document, collection, callback) { // Get the documents collection var coll = db.collection(collection); // Insert some documents coll.insert(document, function(err, result) { assert.equal(err, null); console.log("Inserted " + result.result.n + " documents into the document collection " + collection); callback(result); }); };
  • 136. var assert = require('assert'); exports.insertDocument = function(db, document, collection, callback) { // Get the documents collection var coll = db.collection(collection); // Insert some documents coll.insert(document, function(err, result) { assert.equal(err, null); console.log("Inserted " + result.result.n + " documents into the document collection " + collection); callback(result); }); }; exports.findDocuments = function(db, collection, callback) { // Get the documents collection var coll = db.collection(collection); // Find some documents coll.find({}).toArray(function(err, docs) { assert.equal(err, null); callback(docs); }); }; exports.removeDocument = function(db, document, collection, callback) { // Get the documents collection var coll = db.collection(collection); // Delete the document coll.deleteOne(document, function(err, result) { assert.equal(err, null); console.log("Removed the document " + document); callback(result);
  • 137. // Find some documents coll.find({}).toArray(function(err, docs) { assert.equal(err, null); callback(docs); }); }; exports.removeDocument = function(db, document, collection, callback) { // Get the documents collection var coll = db.collection(collection); // Delete the document coll.deleteOne(document, function(err, result) { assert.equal(err, null); console.log("Removed the document " + document); callback(result); }); }; exports.updateDocument = function(db, document, update, collection, callback) { // Get the documents collection var coll = db.collection(collection); // Update document coll.updateOne(document , { $set: update }, null, function(err, result) { assert.equal(err, null); console.log("Updated the document with " + update); callback(result); }); };
  • 138. var MongoClient = require('mongodb').MongoClient, assert = require('assert'); var dboper = require('./operations'); var url = 'mongodb://localhost:27017/conFusion'; MongoClient.connect(url, function (err, db) { assert.equal(null, err); console.log("Connected correctly to server"); dboper.insertDocument(db, { name: "Vadonut", description: "Test" }, "dishes", function (result) { console.log(result.ops); dboper.findDocuments(db, "dishes", function (docs) { console.log(docs); dboper.updateDocument(db, { name: "Vadonut" }, { description: "Updated Test" }, "dishes", function (result) { console.log(result.result); dboper.findDocuments(db, "dishes", function (docs) { console.log(docs) db.dropCollection("dishes", function (result) { console.log(result); db.close(); }); }); }); }); }); });
  • 139. mongooseLet's face it, writing MongoDB validation, casting and business logic boilerplate is a drag. That's why we wrote Mongoose.
  • 140. O Mongoose é um módulo focado para a criação de models, isso significa que com ele criaremos objetos persistentes modelando seus atributos através do objeto mongoose.Schema. mongoose
  • 142. mongoose var mongoose = require('mongoose'); var Schema = mongoose.Schema; // create a schema var thingSchema = new Schema({ name: { type: String, required: true, unique: true }, description: { type: String, required: true } }, { timestamps: true }); var things = mongoose.model('thing', thingSchema); // make this available to our Node applications module.exports = things;
  • 143. mongoose var mongoose = require('mongoose'), assert = require('assert'); var things = require('./things'); // Connection URL var url = 'mongodb://localhost:27017/db_things'; mongoose.connect(url); var db = mongoose.connection; db.on('error', console.error.bind(console, 'connection error:')); db.once('open', function () { console.log("Connected correctly to server"); // create a new user var newThing = things({ name: 'Cadeira', description: 'Cadeira Inteligente' }); // save the user newThing.save(function (err) { if (err) throw err; console.log('thing created!'); things.find({}, function (err, things) { if (err) throw err; console.log(things); db.close(); // }); }); }); });
  • 144. Schemas “Composto" mongoose var mongoose = require('mongoose'); var Schema = mongoose.Schema; var commentSchema = new Schema({ rating: { type: Number, min: 1, max: 5, required: true }, comment: { type: String, required: true }, author: { type: String, required: true } }, { timestamps: true }); . . . . . . var thingSchema = new Schema({ name:{ type:String, required:true, unique:true }, description:{ type:String, required:true }, comments:[commentSchema] }, { timestamps:true }); var Things = mongoose.model('thing', thingSchema); module.exports = Things;
  • 145. mongoose var mongoose = require('mongoose'); var assert = require('assert'); var Things = require('./models/things-2.js'); var url = 'mongodb://localhost:27017/conFusion'; mongoose.connect(url); var db = mongoose.connection; db.on('error', console.error.bind(console, 'connection error:')); db.once('open', function(){ console.log("Connected correctly to server"); // create a new user var newThing = Things({ name: 'Cadeira Legal', description: 'cadeira mágica', comments: [ { rating: 3, comment: 'This is insane', author: 'Matt Daemon' } ] }); newThing.save(function(err, thing){ if (err) throw err; console.log('Thing created!'); console.log(thing); var id = thing._id; setTimeout(function(){ Things.findByIdAndUpdate(id, { $set:{ description: 'udpated test' }
  • 146. mongoose if (err) throw err; console.log('Thing created!'); console.log(thing); var id = thing._id; setTimeout(function(){ Things.findByIdAndUpdate(id, { $set:{ description: 'udpated test' } }, { new:true }).exec(function(err,thing){ if (err) throw err; console.log('Updated thing!'); console.log(thing); thing.comments.push({ rating: 5, comment: 'I'm getting a sinking feeling!', author: 'Leonardo di Carpaccio' }); thing.save(function (err, thing) { console.log('Updated Comments!'); console.log(thing); db.collection('things').drop(function () { db.close(); }); }); }); }, 3000); }); });
  • 148. • Usando o express-generator crie um novo projeto de sua escolha; • Nesse projeto você deve criar 3 schemas do mongoose, sendo que pelo menos um deles será utilizado como "sub schema” do outro; • Crie um controller para cada um dos schemas, cada controle deve conter operações de CRUD dos schemas; • Crie um arquivo javascript para chamar e testar os controllers;
  • 149. REST API com Express, MongoDB and Mongoose
  • 152. REST API Toda requisição precisa ser decodificada e em seguida mapeada de acordo com sua “natureza”: Router().route(’/uri’) .get( ) .post ( ) Mongoose Schema + MongoDB Things.find({}, ); Things.create( );
  • 153. REST API Toda requisição precisa ser decodificada e em seguida mapeada de acordo com sua “natureza”:
  • 154. Crie o projeto utilizando o express-generator: $ express --view=pug rest-api-exercise create : rest-api-exercise create : rest-api-exercise/package.json create : rest-api-exercise/app.js create : rest-api-exercise/public create : rest-api-exercise/views create : rest-api-exercise/views/index.pug create : rest-api-exercise/views/layout.pug create : rest-api-exercise/views/error.pug create : rest-api-exercise/routes create : rest-api-exercise/routes/index.js create : rest-api-exercise/routes/users.js create : rest-api-exercise/bin create : rest-api-exercise/bin/www create : rest-api-exercise/public/javascripts create : rest-api-exercise/public/images create : rest-api-exercise/public/stylesheets create : rest-api-exercise/public/stylesheets/style.css $ npm install $ npm install mongoose mongoose-currency --save Instale os módulos node necessários:
  • 155. Crie a pasta models e dentro dela o schema books.js var mongoose = require('mongoose'); var Schema = mongoose.Schema; // add the Currency type to the Mongoose Schema types require('mongoose-currency').loadType(mongoose); var Currency = mongoose.Types.Currency; var commentSchema = new Schema({ rating: { type: Number, min: 1, max: 5, required: true }, comment: { type: String, required: true }, author: {type: String, required: true} }, { timestamps: true} ); var bookSchema = new Schema({ name:{ type:String, required:true, unique:true }, image:{ type:String, required:true }, category:{ type:String, required:true }, label: { type: String, default: '' }, price: { type:Currency }, description:{ type:String, required:true }, comments:[commentSchema] }, { timestamps:true } ); var Books = mongoose.model('Book', bookSchema); module.exports = Books;
  • 156. Dentro da pasta routes crie o arquivo bookRouter.js var express = require('express'); var bodyParser = require('body-parser'); var mongoose = require('mongoose'); var Books = require('../models/books'); var bookRouter = express.Router(); bookRouter.use(bodyParser.json()); bookRouter.route('/') .get(function (req, res, next) { Books.find({}, function (err, book) { if (err) throw err; res.json(book); }); }) .post(function (req, res, next) { Books.create(req.body, function (err, book) { if (err) throw err; console.log('Book created!'); var id = book._id; res.writeHead(200, { 'Content-Type': 'text/plain' }); res.end('Added the book with id: ' + id); }); }) .delete(function (req, res, next) { Books.remove({}, function (err, resp) { if (err) throw err; res.json(resp);
  • 157. .delete(function (req, res, next) { Books.remove({}, function (err, resp) { if (err) throw err; res.json(resp); }); }); bookRouter.route('/:bookId') .get(function (req, res, next) { Books.findById(req.params.bookId, function (err, book) { if (err) throw err; res.json(book); }); }) .put(function (req, res, next) { Books.findByIdAndUpdate(req.params.bookId, { $set: req.body }, { new: true }, function (err, book) { if (err) throw err; res.json(book); }); }) .delete(function (req, res, next) { Books.findByIdAndRemove(req.params.bookId, function (err, resp) { if (err) throw err; res.json(resp); }); }); bookRouter.route('/:bookId/comments') .get(function (req, res, next) { Books.findById(req.params.bookId, function (err, book) { if (err) throw err; res.json(book.comments); }); })
  • 158. bookRouter.route('/:bookId/comments') .get(function (req, res, next) { Books.findById(req.params.bookId, function (err, book) { if (err) throw err; res.json(book.comments); }); }) .post(function (req, res, next) { Books.findById(req.params.bookId, function (err, book) { if (err) throw err; book.comments.push(req.body); book.save(function (err, book) { if (err) throw err; console.log('Updated Comments!'); res.json(book); }); }); }) .delete(function (req, res, next) { Books.findById(req.params.bookId, function (err, book) { if (err) throw err; for (var i = (book.comments.length - 1); i >= 0; i--) { book.comments.id(book.comments[i]._id).remove(); } book.save(function (err, result) { if (err) throw err; res.writeHead(200, { 'Content-Type': 'text/plain' }); res.end('Deleted all comments!'); }); }); }); bookRouter.route('/:bookId/comments/:commentId') .get(function (req, res, next) { Books.findById(req.params.bookId, function (err, book) { if (err) throw err;
  • 159. bookRouter.route('/:bookId/comments/:commentId') .get(function (req, res, next) { Books.findById(req.params.bookId, function (err, book) { if (err) throw err; res.json(book.comments.id(req.params.commentId)); }); }) .put(function (req, res, next) { // We delete the existing commment and insert the updated // comment as a new comment Books.findById(req.params.bookId, function (err, book) { if (err) throw err; book.comments.id(req.params.commentId).remove(); book.comments.push(req.body); book.save(function (err, book) { if (err) throw err; console.log('Updated Comments!'); res.json(book); }); }); }) .delete(function (req, res, next) { Books.findById(req.params.bookId, function (err, book) { book.comments.id(req.params.commentId).remove(); book.save(function (err, resp) { if (err) throw err; res.json(resp); }); }); }); module.exports = bookRouter;
  • 160. 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 index = require('./routes/index'); var users = require('./routes/users'); var bookRouter = require('./routes/bookRouter'); var mongoose = require('mongoose'); var url = 'mongodb://localhost:27017/books'; mongoose.connect(url); var db = mongoose.connection; db.on('error', console.error.bind(console, 'connection error:')); db.once('open', function () { // we're connected! console.log("Connected correctly to server"); }); var app = express(); // view engine setup app.set('views', path.join(__dirname, 'views')); app.set('view engine', 'pug'); // uncomment after placing your favicon in /public //app.use(favicon(path.join(__dirname, 'public', 'favicon.ico'))); Ajuste o arquivo app.js criado pelo express-generator
  • 161. // view engine setup app.set('views', path.join(__dirname, 'views')); app.set('view engine', 'pug'); // uncomment after placing your favicon in /public //app.use(favicon(path.join(__dirname, 'public', 'favicon.ico'))); app.use(logger('dev')); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: false })); app.use(cookieParser()); app.use(express.static(path.join(__dirname, 'public'))); app.use('/', index); app.use('/books', bookRouter); app.use('/users', users); // catch 404 and forward to error handler app.use(function(req, res, next) { var err = new Error('Not Found'); err.status = 404; next(err); }); // error handler app.use(function(err, req, res, next) { // set locals, only providing error in development res.locals.message = err.message; res.locals.error = req.app.get('env') === 'development' ? err : {}; // render the error page res.status(err.status || 500); res.render('error'); }); module.exports = app;
  • 164. Exercício Agora continuando o exemplo, crie uma rota, schema e API similar a criada para os “tipos" CD e Obra de Arte.
  • 166. Client Serverrequest a protected resource request username and password send username and password returns requested resource
  • 167. Express and Basic Authentication function auth (req, res, next) { console.log(req.headers); var authHeader = req.headers.authorization; if (!authHeader) { var err = new Error('You are not authenticated!'); err.status = 401; next(err); return; } var auth = new Buffer(authHeader.split(' ')[1], 'base64').toString().split(':'); var user = auth[0]; var pass = auth[1]; if (user == 'admin' && pass == 'password') { next(); // authorized } else { var err = new Error('You are not authenticated!'); err.status = 401; next(err); } } app.use(auth);
  • 168. var express = require('express'); var morgan = require('morgan'); var hostname = 'localhost'; var port = 3000; var app = express(); app.use(morgan('dev')); function auth (req, res, next) { console.log(req.headers); var authHeader = req.headers.authorization; if (!authHeader) { var err = new Error('You are not authenticated!'); err.status = 401; next(err); return; } var auth = new Buffer(authHeader.split(' ')[1], 'base64').toString().split(':'); var user = auth[0]; var pass = auth[1]; if (user == 'admin' && pass == 'password') { next(); // authorized } else { var err = new Error('You are not authenticated!'); err.status = 401; next(err); } } Express and Basic Authentication
  • 169. app.use(morgan('dev')); function auth (req, res, next) { console.log(req.headers); var authHeader = req.headers.authorization; if (!authHeader) { var err = new Error('You are not authenticated!'); err.status = 401; next(err); return; } var auth = new Buffer(authHeader.split(' ')[1], 'base64').toString().split(':'); var user = auth[0]; var pass = auth[1]; if (user == 'admin' && pass == 'password') { next(); // authorized } else { var err = new Error('You are not authenticated!'); err.status = 401; next(err); } } app.use(auth); app.use(express.static(__dirname + '/public')); app.use(function(err,req,res,next) { res.writeHead(err.status || 500, { 'WWW-Authenticate': 'Basic', 'Content-Type': 'text/plain' }); res.end(err.message); }); app.listen(port, hostname, function(){ console.log(`Server running at http://${hostname}:${port}/`); });
  • 170. Exercício Agora continuando o exemplo, continue o exercício de criação da REST API colocando o controle de acesso aos métodos dos routers.
  • 172. User Authentication with Passport Passport (http://passportjs.og) é uma solução não obstrusiva de autenti- cação especí ca para o Node.js que dá suporte a vários provedores como o Facebook, Twiiter, Google entre outros
  • 173. app.post('/login', passport.authenticate('local', { successRedirect: '/', failureRedirect: '/login' })); Apesar das complexidades envolvidas na autenticação, o código não precisa ser complicado app.post('/login', passport.authenticate('local'), function(req, res) { // If this function gets called, authentication was successful. // `req.user` contains the authenticated user. res.redirect('/users/' + req.user.username); }); Os pedidos de autenticação são tão simples como chamar passport.authenticate () e especificar qual estratégia empregar. Se a autenticação falhar, o Passport responderá com um status 401 não autorizado e todos os manipuladores de rotas adicionais não serão invocado
  • 174. app.post('/login', passport.authenticate('local', { successRedirect: '/', failureRedirect: '/login' })); Um redirecionamento geralmente é emitido após a autenticação de um pedido. Nesse caso, as opções de redirecionamento substituem o comportamento padrão. Após a autenticação bem-sucedida, o usuário será redirecionado para a página inicial. Se a autenticação falhar, o usuário será redirecionado de volta para a página de login para outra tentativa.
  • 175. - app ------ models ---------- user.js <!-- our user model --> ------ routes.js <!-- all the routes for our application --> - config ------ auth.js <!-- will hold all our client secret keys (facebook, twitter, google) --> ------ database.js <!-- will hold our database connection settings --> ------ passport.js <!-- configuring the strategies for passport --> - views ------ index.ejs <!-- show our home page with login links --> ------ login.ejs <!-- show our login form --> ------ signup.ejs <!-- show our signup form --> ------ profile.ejs <!-- after a user logs in, they will see their profile --> - package.json <!-- handle our npm packages --> - server.js <!-- setup our application --> Primeiro vamos criar um novo projeto com a seguinte estrutura:
  • 176. { "name": “passaport-authentication", "main": "server.js", "dependencies" : { "express" : "latest", "ejs" : "latest", "mongoose" : "latest", "passport" : "latest", "passport-local" : "latest", "passport-facebook" : "latest", "passport-twitter" : "latest", "passport-google-oauth" : "latest", "connect-flash" : "latest", "bcrypt-nodejs" : "latest", "body-parser": "latest", "cookie-parser": "latest", "debug": "latest", "morgan": "latest", "serve-favicon": "latest", "express-session":"latest" } } package.json
  • 177. // app/models/user.js var mongoose = require('mongoose'); var bcrypt = require('bcrypt-nodejs'); var userSchema = mongoose.Schema({ local : { email : String, password : String, } }); userSchema.methods.generateHash = function(password) { return bcrypt.hashSync(password, bcrypt.genSaltSync(8), null); }; userSchema.methods.validPassword = function(password) { return bcrypt.compareSync(password, this.local.password); }; module.exports = mongoose.model('User', userSchema);
  • 178. // app/routes.js module.exports = function(app, passport) { app.get('/', function(req, res) { res.render('index.ejs'); }); app.get('/login', function(req, res) { res.render('login.ejs', { message: req.flash('loginMessage') }); }); app.post('/login', passport.authenticate('local-login', { successRedirect : '/profile', failureRedirect : '/login', failureFlash : true })); app.get('/signup', function(req, res) { res.render('signup.ejs', { message: req.flash('signupMessage') }); }); app.post('/signup', passport.authenticate('local-signup', { successRedirect : '/profile', failureRedirect : '/signup', failureFlash : true })); app.get('/profile', isLoggedIn, function(req, res) { res.render('profile.ejs', { user : req.user }); });
  • 179. failureRedirect : '/login', failureFlash : true })); app.get('/signup', function(req, res) { res.render('signup.ejs', { message: req.flash('signupMessage') }); }); app.post('/signup', passport.authenticate('local-signup', { successRedirect : '/profile', failureRedirect : '/signup', failureFlash : true })); app.get('/profile', isLoggedIn, function(req, res) { res.render('profile.ejs', { user : req.user }); }); app.get('/logout', function(req, res) { req.logout(); res.redirect('/'); }); }; function isLoggedIn(req, res, next) { if (req.isAuthenticated()) return next(); res.redirect('/'); }
  • 180. // config/passport.js var LocalStrategy = require('passport-local').Strategy; var User = require('../app/models/user'); module.exports = function(passport) { passport.serializeUser(function(user, done) { done(null, user.id); }); passport.deserializeUser(function(id, done) { User.findById(id, function(err, user) { done(err, user); }); }); passport.use('local-signup', new LocalStrategy({ usernameField : 'email', passwordField : 'password', passReqToCallback : true }, function(req, email, password, done) { User.findOne({ 'local.email' : email }, function(err, user) { if (err) return done(err); if (user) { return done(null, false, req.flash('signupMessage', 'That email is already taken.')); } else { var newUser = new User(); newUser.local.email = email; newUser.local.password = newUser.generateHash(password); newUser.save(function(err) { if (err) throw err; return done(null, newUser); });
  • 181. passwordField : 'password', passReqToCallback : true }, function(req, email, password, done) { User.findOne({ 'local.email' : email }, function(err, user) { if (err) return done(err); if (user) { return done(null, false, req.flash('signupMessage', 'That email is already taken.')); } else { var newUser = new User(); newUser.local.email = email; newUser.local.password = newUser.generateHash(password); newUser.save(function(err) { if (err) throw err; return done(null, newUser); }); } }); })); passport.use('local-login', new LocalStrategy({ usernameField : 'email', passwordField : 'password', passReqToCallback : true }, function(req, email, password, done) { User.findOne({ 'local.email' : email }, function(err, user) { if (err) return done(err); if (!user) return done(null, false, req.flash('loginMessage', 'No user found.')); if (!user.validPassword(password)) return done(null, false, req.flash('loginMessage', 'Oops! Wrong password.'));
  • 182. newUser.local.password = newUser.generateHash(password); newUser.save(function(err) { if (err) throw err; return done(null, newUser); }); } }); })); passport.use('local-login', new LocalStrategy({ usernameField : 'email', passwordField : 'password', passReqToCallback : true }, function(req, email, password, done) { User.findOne({ 'local.email' : email }, function(err, user) { if (err) return done(err); if (!user) return done(null, false, req.flash('loginMessage', 'No user found.')); if (!user.validPassword(password)) return done(null, false, req.flash('loginMessage', 'Oops! Wrong password.')); return done(null, user); }); })); };
  • 183. // server.js var express = require('express'); var port = process.env.PORT || 8080; var mongoose = require('mongoose'); var passport = require('passport'); var flash = require('connect-flash'); var logger = require('morgan'); var cookieParser = require('cookie-parser'); var bodyParser = require('body-parser'); var session = require('express-session') var configDB = require('./config/database.js'); var app = express(); mongoose.connect(configDB.url); app.use(logger('dev')); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: false })); app.use(cookieParser()); app.set('view engine', 'ejs'); app.use(session({secret: 'winteriscomming'})) app.use(passport.initialize()); app.use(passport.session()); app.use(flash()); //ORDEM IMPORTA!!! require('./config/passport')(passport); require('./app/routes.js')(app, passport); app.listen(port); console.log('The magic happens on port ' + port);
  • 184. // config/database.js module.exports = { 'url' : 'mongodb://localhost/passport' }; https://goo.gl/EQPD2Z Crie o arquivo database.js com a URL do seu banco de dados Faça o download das views e copie para a pasta views
  • 186. Entre no site "Facebook Developers" e crie a sua aplicação. Defina a sua callback URL para:  http://localhost:8080/auth/facebook/callback
  • 187. module.exports = { 'facebookAuth' : { 'clientID' : 'your-secret-clientID-here', // App ID 'clientSecret' : 'your-client-secret-here', // App Secret 'callbackURL' : 'http://localhost:8080/auth/facebook/callback' } };
  • 188. // config/passport.js var LocalStrategy = require('passport-local').Strategy; var FacebookStrategy = require('passport-facebook').Strategy; var User = require('../app/models/user'); var configAuth = require('./auth'); module.exports = function(passport) { passport.serializeUser(function(user, done) { done(null, user.id); }); passport.deserializeUser(function(id, done) { User.findById(id, function(err, user) { done(err, user); }); }); passport.use(new FacebookStrategy({ clientID : configAuth.facebookAuth.clientID, clientSecret : configAuth.facebookAuth.clientSecret, callbackURL : configAuth.facebookAuth.callbackURL }, function(token, refreshToken, profile, done) { process.nextTick(function() { User.findOne({ 'facebook.id' : profile.id }, function(err, user) { if (err) return done(err); if (user) { return done(null, user); } else {
  • 189. passport.use(new FacebookStrategy({ clientID : configAuth.facebookAuth.clientID, clientSecret : configAuth.facebookAuth.clientSecret, callbackURL : configAuth.facebookAuth.callbackURL }, function(token, refreshToken, profile, done) { process.nextTick(function() { User.findOne({ 'facebook.id' : profile.id }, function(err, user) { if (err) return done(err); if (user) { return done(null, user); } else { var newUser = new User(); newUser.facebook.id = profile.id; newUser.facebook.token = token; newUser.facebook.name = profile.name.givenName + ' ' + profile.name.familyName; newUser.facebook.email = profile.emails[0].value; console.log(profile); newUser.save(function(err) { if (err) throw err; return done(null, newUser); }); } }); }); })); };
  • 190. // app/routes.js module.exports = function(app, passport) { app.get('/', function(req, res) { res.render('index.ejs'); }); app.get('/profile', isLoggedIn, function(req, res) { res.render('profile.ejs', { user : req.user }); }); app.get('/auth/facebook', passport.authenticate('facebook', { scope : 'email' })); app.get('/auth/facebook/callback', passport.authenticate('facebook', { successRedirect : '/profile', failureRedirect : '/' })); app.get('/logout', function(req, res) { req.logout(); res.redirect('/'); }); }; function isLoggedIn(req, res, next) { if (req.isAuthenticated()) return next(); res.redirect('/'); }
  • 191. <!-- views/index.ejs --> <!doctype html> <html> <head> <title>Node Authentication</title> <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.2/css/ bootstrap.min.css"> <!-- load bootstrap css --> <link rel="stylesheet" href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font- awesome.min.css"> <!-- load fontawesome --> <style> body { padding-top:80px; } </style> </head> <body> <div class="container"> <div class="jumbotron text-center"> <h1><span class="fa fa-lock"></span> Node Authentication</h1> <p>Login or Register with:</p> <a href="/auth/facebook" class="btn btn-primary"><span class="fa fa-facebook"></span> Facebook</a> </div> </div> </body> </html>
  • 192. <!-- views/profile.ejs --> <!doctype html> <html> <head> <title>Node Authentication</title> <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.2/css/bootstrap.min.css"> <link rel="stylesheet" href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.min.css"> <style> body { padding-top:80px; word-wrap:break-word; } </style> </head> <body> <div class="container"> <div class="page-header text-center"> <h1><span class="fa fa-anchor"></span> Profile Page</h1> <a href="/logout" class="btn btn-default btn-sm">Logout</a> </div> <div class="row"> <!-- FACEBOOK INFORMATION --> <div class="col-sm-6"> <div class="well"> <h3 class="text-primary"><span class="fa fa-facebook"></span> Facebook</h3> <p> <strong>id</strong>: <%= user.facebook.id %><br> <strong>token</strong>: <%= user.facebook.token %><br> <strong>email</strong>: <%= user.facebook.email %><br> <strong>name</strong>: <%= user.facebook.name %> </p> </div> </div>
  • 193. <html> <head> <title>Node Authentication</title> <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.2/css/bootstrap.min.css"> <link rel="stylesheet" href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.min.css"> <style> body { padding-top:80px; word-wrap:break-word; } </style> </head> <body> <div class="container"> <div class="page-header text-center"> <h1><span class="fa fa-anchor"></span> Profile Page</h1> <a href="/logout" class="btn btn-default btn-sm">Logout</a> </div> <div class="row"> <!-- FACEBOOK INFORMATION --> <div class="col-sm-6"> <div class="well"> <h3 class="text-primary"><span class="fa fa-facebook"></span> Facebook</h3> <p> <strong>id</strong>: <%= user.facebook.id %><br> <strong>token</strong>: <%= user.facebook.token %><br> <strong>email</strong>: <%= user.facebook.email %><br> <strong>name</strong>: <%= user.facebook.name %> </p> </div> </div> </div> </div> </body> </html>
  • 194. Exercício Troque o método de autenticação do exercício da REST API para aceitar a autenticação via facebook.
  • 196. • Crie um novo projeto completo com: • Livros, DVDs, CDs e Autor; • Cada uma das 3 primeiras entidade possui um relacionamento com Autor (cada uma possui um Autor); • Crie os métodos REST para o CRUD das 4 entidades; • Utilizar o MongoDB e autenticação com o Facebook ou Google ou Autenticação simples; • Os métodos GET podem ser acessados sem que o usuário esteja autenticado; • Os métodos POST, UPDATE e DELETE só podem ser acessados por usuários autenticados; https://goo.gl/npBz5q