Home

Awesome

#Node.js Workshop

Após finalizar o processo de instalação do Node.js, crie uma pasta para o projeto.

Exercício 1 @ 10 minutos

1 - Crie um módulo chamado index (index.js), ele será o entry-point e deverá ser invocado da seguinte forma:

node index.js

2 - Dentro do módulo index, crie uma função construtora (aquela que utiliza o operador new) chamada Livro, contendo as propriedades titulo, autor, isbn, paginas, ano, editora, idioma e assunto.

var Livro = function (titulo, autor, isbn, paginas, ano, editora, idioma, assunto) {
	this.titulo = titulo;
	this.autor = autor;
	this.isbn = isbn;
	this.paginas = paginas;
	this.ano = ano;
	this.editora = editora;
	this.idioma = idioma;
	this.assunto = assunto;
};

3 - Crie também um array de livros, incluindo alguns livros diretamente dentro do array.

var livros = [
	new Livro(...),
	new Livro(...),
	new Livro(...)
];

4 - Por fim, utilizando a função forEach, percorra o array de livros exibindo cada um deles.

livros.forEach(function (livro) {
	console.log(livro);
});

Exercício 2 (Sistema de Módulos) @ 30 minutos

1 - Crie uma pasta chamada domain e lá crie um módulo chamado livro (livro.js).

2 - Mova a função construtora Livro para lá, exportando-a na forma de uma função.

var Livro = function (titulo, autor, isbn, paginas, ano, editora, idioma, assunto) {
	this.titulo = titulo;
	this.autor = autor;
	this.isbn = isbn;
	this.paginas = paginas;
	this.ano = ano;
	this.editora = editora;
	this.idioma = idioma;
	this.assunto = assunto;
};

module.exports = Livro;

3 - Crie uma pasta chamada data e lá crie um módulo chamado livros (livros.js)

4 - Mova o array de livros para lá, utilizando a função require para importar a função construtora Livro.

var Livro = require('../domain/livro');

var livros = [
	new Livro(...),
	new Livro(...),
	new Livro(...)
];

module.exports = livros;

4 - Crie uma pasta chamada service e dentro crie um módulo chamado livrosService (livrosService.js).

5 - Mova a função forEach para dentro de uma função chamada exibirLivros, responsável por percorrer o array de livros e exibir seus detalhes.

var livros = require('../data/livros');

var exibirLivros = function () {
	livros.forEach(function (livro) {
		console.log(livro);
	});
};

module.exports = {
	exibirLivros: exibirLivros
};

6 - Por fim, no módulo index, faça o require do módulo livrosService e invoque a função exibirLivros.

var livrosService = require('./service/livrosService');

livrosService.exibirLivros();

Exercício 3 (Global Objects) @ 20 minutos

1 - No módulo index, faça a leitura do teclado e imprima tudo que é digitado.

process.stdin.on('readable', function () {
	var data = process.stdin.read();
	if (data) console.log(data.toString());
});

2 - Crie uma pasta chamada infra e crie um módulo chamado teclado (teclado.js), movendo a função de leitura do teclado para o módulo teclado, recebendo um callback que será executado sempre que algo for digitado.

var aoDigitar = function (callback) {
	process.stdin.on('readable', function () {
		var data = process.stdin.read();
		var linha = (data) ? data.toString() : '';
		linha = linha.replace(/\n/, '');
		if (linha) callback(linha);
	});
};

module.exports = {
	aoDigitar: aoDigitar
};

3 - No módulo index, utilize a função require para importar o módulo teclado.

var livrosService = require('./service/livrosService');
var teclado = require('./infra/teclado.js');

teclado.aoDigitar(function (linha) {
	console.log(linha);
});

4 - No módulo livrosService, crie uma função para exibirLivrosPorTitulo, utilizando o que foi digitado para realizar a busca.

var livros = require('../data/livros');

var exibirLivrosPorTitulo = function (titulo) {
	var livrosEncontrados = livros.filter(function (livro) {
	  return livro.titulo.indexOf(titulo) > -1;
	});
	if (livrosEncontrados.length === 0) {
		console.log("Nenhum livro foi encontrado!");
		return;
	}
	livrosEncontrados.forEach(function(livro) {
		console.log(livro);
	});
};

module.exports = {
	exibirLivrosPorTitulo: exibirLivrosPorTitulo
};

5 - Modifique o módulo index para invocar a função exibirLivrosPorTitulo sempre que alguma linha for digitada.

var livrosService = require('./service/livrosService');
var teclado = require('./infra/teclado.js');

teclado.aoDigitar(function (linha) {
	livrosService.exibirLivrosPorTitulo(linha);
});

6 - Adicione a possibilidade de digitar /q para sair, utilizando a função process.exit()

var livrosService = require('./service/livrosService');
var teclado = require('./infra/teclado.js');

teclado.aoDigitar(function (linha) {
	if (linha === '/q') process.exit();
	livrosService.exibirLivrosPorTitulo(linha);
});

7 - Para dar a impressão que a busca está sendo realizada, faça com que a função exibirLivrosPorTitulo seja invocada com um atraso de 1000ms.

var livrosService = require('./service/livrosService');
var teclado = require('./infra/teclado.js');

teclado.aoDigitar(function (linha) {
	if (linha === '/q') process.exit();
	setTimeout(function () {
		livrosService.exibirLivrosPorTitulo(linha);
	}, 1000);
});

Exercício 4 (Code Module) @ 30 minutos

1 - No módulo livros, obtenha a lista de livros diretamente do arquivo livros.csv, utilizando função readFile do módulo fs, criando o array de livros a partir do arquivo lido.

var fs = require('fs');

var livros = [];

var carregarLivros = function () {
	fs.readFile('./data/livros.csv', 'utf8', function (err, csv) {
		if (err) {
			console.log(err);
			return;
		}
		var linhas = csv.split('\n');
		linhas.forEach(function (linha) {
			var propriedades = linha.split(';');
			var livro = new Livro(propriedades[0], propriedades[1], propriedades[2], propriedades[3], propriedades[4], propriedades[5], propriedades[6], propriedades[7]);
			livros.push(livro);
		})
	});
};

carregarLivros();

module.exports = livros;

2 - Crie um módulo chamado zip para comprimir o arquivo livros.csv utilizando o módulo zlib.

var fs = require('fs');
var path = require('path');
var gzip = require('zlib').createGzip();
  
var inp = fs.createReadStream(path.join(__dirname, '/livros.csv'));
var out = fs.createWriteStream(path.join(__dirname, '/livros.zip'));
inp.pipe(gzip).pipe(out);

3 - Crie outro módulo chamado unzip para descomprimir o arquivo livros.zip.

4 - Modifique a função carregarLivros, do módulo livros, para descomprimir o arquivo livros.zip antes de montar o array.

var carregarLivros = function () {
	fs.readFile(__dirname + '/livros.zip', function (err, zip) {
		if (err) {
			console.log(err);
			return;
		}
		zlib.unzip(zip, function (err, data) {
			if (err) {
				console.log(err);
				return;
			}
			var csv = data.toString('utf8');
			var linhas = csv.split('\n');
			linhas.forEach(function (linha) {
				var propriedades = linha.split(';');
				var livro = new Livro(propriedades[0], propriedades[1], propriedades[2], propriedades[3], propriedades[4], propriedades[5], propriedades[6], propriedades[7]);
				livros.push(livro);
			});
		});
	});
};

4 - Crie a pasta http, juntamente com o módulo livrosHttp, utilizando o módulo http para listar os livros pela web.

var http = require('http');
var livrosService = require('../service/livrosService');
  
var server = http.createServer(function (req, res) {
  	res.writeHead(200, {
    	'Content-Type': 'text/html;charset=UTF-8'
  	});
  	res.write("<h1>Livros</h1>")
  	var livros = livrosService.getLivros();
	livros.forEach(function (livro) {
		res.write("<h4>" + livro.titulo + "</h4>");
		res.write("<h5>" + livro.autor + "</h5><br/>");
	});
	res.end();
});
module.exports = server;

5 - Mude o módulo index para que seja possível rodar por meio do modo teclado ou de http, passando por parâmetro a opção -http, permitindo com que seja possível acessar a lista de livros pelo navegador na url http://localhost:3000

var livrosService = require('./service/livrosService');
var livrosHttp = require('./http/livrosHttp');
var teclado = require('./infra/teclado.js');

var httpMode = process.argv.some(function (arg) {
	return arg === '-http';
});

if (httpMode) {
	console.log("Http Mode");
	livrosHttp.listen(3000);
	return;
}

console.log("Keyboard Mode");
teclado.aoDigitar(function (linha) {
	if (linha === '/q') process.exit();
	setTimeout(function () {
		livrosService.exibirLivrosPorTitulo(linha);
	}, 1000);
});

Para rodar no modo http, utilize o comando:

node index.js -http

6 - Crie a função getLivrosPorTitulo no módulo livrosService. Não se esqueça de exportá-la.

var getLivrosPorTitulo = function (titulo) {
	if (!titulo) return livros;
	return livros.filter(function (livro) {
	  return livro.titulo.indexOf(titulo) > -1;
	});
};

7 - Modifique o módulo livrosHttp para receber parâmetros pela url e realizar a busca por título, utilizando o módulo url.

var http = require('http');
var url = require('url');
var livrosService = require('../service/livrosService');
  
var server = http.createServer(function (req, res) {
	var titulo = url.parse(req.url, true).query.titulo;
  	res.writeHead(200, {
    	'Content-Type': 'text/html;charset=UTF-8'
  	});
  	res.write('<h1>Livros: '+ titulo + '</h1>');
  	var livros = livrosService.getLivrosPorTitulo(titulo);
	livros.forEach(function (livro) {
		res.write('<h4>' + livro.titulo + '</h4>');
		res.write('<h5>' + livro.autor + '</h5><br/>');
	});
	res.end();
});

module.exports = server;

Exercício 5 (Express) @ 10 minutos

1 - Crie o arquivo package.json:

npm init

2 - Instale o Express utilizando o NPM:

npm install express --save

3 - Crie uma chamada pasta api e o módulo livrosApi (livrosApi.js).

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

module.exports = app;

4 - Defina uma rota utilizando o método get chamada /livros, retornando um JSON.

var express = require('express');
var app = express();
var livrosService = require('../service/livrosService');

app.get('/livros', function (req, res) {
	res.json(livrosService.getLivros());
});

module.exports = app;

5 - Modifique o módulo index para rodar em modo api com o parâmetro -api

var apiMode = process.argv.some(function (arg) {
	return arg === '-api';
});

if (apiMode) {
	console.log("Api Mode");
	livrosApi.listen(3000);
	return;
}

Para rodar, utilize o comando:

node index.js -api