Aula 06 - Node.js
Apresenta o gerenciador de pacotes NPM e o framework Node.js
Exemplos de aula
Introdução

O Node.js é um interpretador de código javascript focado na criação de aplicações assíncronas de alta escalabilidade no lado de servidores.
Site do Node.js
A criação de um script para ser interpretado pelo Node.js é possivelmente mais simples que sua utilização no navegador. Levando sempre em consideração que a linguagem (javascript) utilizada no node é a mesma utilziada no navegador, iremos criar um novo arquivo e incluir no script um comando simples:
console.log("Olá Mundo")
Para executar esse arquivo, é necessário acessar prompt de comando (o que pode ser feito pelo cmd, no windows, ou pela própria IDE do vscode). Em seguida usaremos o comando node para iniciar o script:
node index.js
Caso tudo esteja certo, receberemos a mensagem interpretada pelo Node.js:
Olá mundo!
Pronto! Criamos nosso primeiro script usando o Node.js.
Gerenciador de Pacotes
O NPM é uma ferramenta usada por mais de 11 milhões de programadores para gerenciamento de pacotes na linguagem javascript.
O NPM consiste em um cliente de linha de comando e um repositório online de pacotes públicos e privados, que possui atualmente quase meio milhão de pacotes.
Através do NPM é possivel, por exemplo, submeter e compartilhar projetos no repositório, realizar a instalação automática de dependências, organizar os metadados do projeto, auditar falhas de segurança e gerenciar scripts de execução.
Para iniciar um novo pacote npm, basta executar o comando no prompt de comando:
npm init
Após preencher os metadados do projeto, um arquivo chamado package.json é criado com estas informações. Este arquivo será utilizado pelo npm para apontar dependências, informações e configurações dos pacotes utilizados, assim como scripts de inicialização.
{
"name": "meuProjeto",
"version": "1.0.0",
"description": "",
"main": "index.js",
"dependencies": {
"level": "^5.0.1",
"request": "^2.88.0"
},
"devDependencies": {},
"scripts": {
"test": "echo "Error: no test specified" && exit 1"
},
"author": "",
"license": "ISC"
}
Não se preocupe com os dados desse arquivo por enquanto. Eles serão úteis apenas mais a frente.
O NPM é um gerenciado de pacotes que também tem a função de gerenciar as dependências de uma aplicação. Isso significa que ele é capaz de gerenciar outras bibliotecas externas que serão necessárias para que o programa funcione corretamente.
Para instalar uma nova dependência no projeto atual, execute o comando:
npm install nome_do_pacote
O comando acima deverá criar uma pasta chamada node_modules, que contém todas as dependências do projeto. Para efeitos de controle de versão, é geralmente seguro adicionar esta pasta aos arquivos ignorados pelo git no arquivo .gitignore.
Para um arquivo .gitignore completo, utilize o site gitignore.io, criando o arquivo com a opçãonode
Geralmente é comum utilizar a opção --save e --save-dev para salvar os pacotes nas dependências do projeto, para que possam ser reinstalados e atualizados posteriormente.
O mesmo pacote pode ser removido das dependências utilizando o comando:
npm remove nome_do_pacote
Quando utilizamos um pacote que já possui algumas dependências configuradas (um projeto que acabou de ser descarregado da web, por exemplo), é comum que as dependências não estejam disponíveis por economia de espaço ou questõe legais. Para instalar ou atualizar as dependências de um projeto, utilize o comando:
npm install
Isso faz com que todas as dependencias que foram previamente salvas no projeto sejam instaladas/atualizadas.
O NPM também pode ser utilizado para configurar processos comuns da aplicação, como inicialização e testes.
Para facilitar o processo de inicialização, é possivel adicionar novos scripts para inicialização do projeto, como no caso abaixo:
...
"scripts": {
"test": "echo "Error: no test specified" && exit 1",
"start": "node index.js"
},
...
Repare que neste caso, incluímos o script "start" com o comando node index.js
Sendo assim, vamos chamar o npm junto do nome do script no parâmetro para iniciar a aplicação:
npm start
Dessa forma não é necessário lembrar qual o comando e o arquivo para iniciar a aplicação. Boa parte das bibliotecas são escritas com isso em mente, então geralmente é possível executar qualquer aplicação Node dessa forma.
Programando com Node.js
O console do node pode ser acessado diretamente no bash, oferecendo o mesmo suporte para debugging simples similar ao console fornecido pelos navegadores.
Imprimindo no console
console.log("Olá mundo!")
console.warn("Isto é um aviso!")
console.error(new Error("Isto é um erro!"))
O Node possui uma função especifica para importação de bibliotecas. Algumas delas estão disponíveis nativamente (não é necessário instalar), enquanto outras exigem o uso do comando npm install ou instalação manual. De qualquer forma, fazemos a importação dos arquivos para nosso script através da função require()
const readline = require('meu_pacote')
Essa importação é feita para o script no momento da inicialização do programa. Também podemos usar esse mesmo comando para importar outros arquivos de dentro do nosso próprio projeto (desde que sejam devidamente exportados), ou mesmo arquivos com conteúdo de texto.
A leitura de entradas do usuário pelo console pode ser realizada importando um módulo chamadoreadline
Criaremos uma interface através do comando createInterface, passando como parâmetro as entradas e saídas do processo atual.
const readline = require('readline')
const bash = readline.createInterface({
input: process.stdin,
output: process.stdout
})
bash.question("Qual a cor da sua camiseta?", function(resposta){
console.log(resposta)
})
O código exemplo, no entanto, é executado de maneira assíncrona.
O Node possui um módulo nativo chamado process que é capaz de acessar informações relacionadas ao processo da aplicação em execução. Isso pode ser extramemente útil em casos onde desejamos controlar o uso de recursos, acessar variáveis de ambiente ou passar parâmetros para a execução do script.
let saida
saida = process.cpuUsage() // Retorna uso da CPU pelo processo atual
saida = process.memoryUsage() // retorna o uso de memória pelo processo atual
saida = process.cwd() // Retorna diretorio atual de trabalho do processo
saida = process.argv // Retorna um vetor com os argumentos passados ao node
saida = process.env // Retorna um objeto com as variáveis de ambiente
console.log(saida)
process.exit(1) // Finaliza o process
Para executar requisições HTTP simples, podemos utilizar uma bilioteca padrão chamadarequest. Para usá-la, é necessário realizar a instalação usando:
npm install request
E a sua sintaxe padrão para requisições do tipo GET:
const request = require('request');
request('http://www.google.com', function (err, resposta, body) {
console.log(body);
})
Outras formas de fazer requisição HTTPNode HTTP Requests
Persistência de Dados
O Node disponibiliza um modulo chamado fs para acessar o sistema de arquivos (file system) do computador. Para incluir esse módulo é necessário realizar a importação usando a funçãorequire().
const fs = require('fs')
Lendo arquivos de texto
Para ler arquivos de texto, podemos utilizar duas versões: o readFileSync() e oreadFile(), funções respectivamente síncrona e assíncrona. O parâmetroencoding é opcional, mas importante.
const fs = require('fs')
var meuArquivo = fs.readFileSync("data.txt", "utf8") //versão síncrona
var meuArquivo = fs.readFile("data.txt", "utf8", function(erro, arquivo){
console.log(arquivo)
}) //versão assíncrona
Escrevendo arquivos de texto
Para escrever em arquivos de texto, podemos utilizar duas versões: o writeFileSync()e owriteFile(), funções respectivamente síncrona e assíncrona.
const fs = require('fs')
var meuArquivo = fs.writeFileSync("data.txt", "meu texto", { encoding: "utf8", flag: "a" }) //versão
síncrona
var meuArquivo = fs.writeFile("data.txt", "meu texto", { encoding: "utf8", flag: "a"}, function(erro){
console.log(erro)
}) //versão assíncrona
A flag a garante que o arquivo será criado e todos os dados serão inseridos no final do seu conteúdo. Outras flags podem ser utilizadas dependendo da situação.
Consulte mais informações em File System Flags
O JSON é um formato muito popular para troca de dados. Sua sintaxe é muito semelhante aos objetos do javascript, pois foi criado exatamente a partir destes. Para salvar um objeto javascript em um arquivo, precisamos convertê-lo primeiro para uma string, usando o seguinte comando:
JSON.stringfy(objeto)
Para realizar o processo contrário, geralmente quando lemos um arquivo JSON e queremos transformá-lo em um objeto, usamos o seguinte comando:
JSON.parse(string)
Por fim, também somos capazes de importar um arquivo JSON diretamente usando a função require(). O resultado da operação já será um objeto javascript (ao invés de texto/string)
let objeto = require('arquivo.json')
Atenção! O uso de require no carregamento de arquivos JSON pode ter um efeito indesejado e problemático para alguns casos. A função require() sempre faz o cache do conteúdo na primeira vez que é chamada, o que significa que se algum script carregar esse mesmo arquivo uma segunda vez, o conteúdo retornado deve ser o do cache ao invés de ler o arquivo novamente. Neste caso, fique atento pois qualquer mudança feita no arquivo de dentro ou de fora do programa não será reconhecida até que o módulo seja totalmente reiniciado.
Mão na Massa
Crie pacote usando npm e implemente um script que receba argumentos, comonode index.js 1 2 3 4 5 6. O script deve retornar a soma total apenas dos argumentos divisíveis por 2.

O objetivo deste exercício é criar um programa capaz de realizar o download e armazenamento dos dados de pokémons especificados pelo usuário em arquivos do tipo json. Para isso, você deve realizar corretamente as três seguintes etapas:
- Crie um script que seja capaz de ler as entradas de um usuário através de argumentos ou da leitura do teclado. O programa deve ser capaz de ler corretamente números entre 1 e 893 que serão salvos dentro de um vetor. Em caso de entrada inválida, o programa deve retornar um erro e encerrar sua execução.
- Utilize o vetor com os números armazenados anteriormente para criar uma requisição GET HTTP para cada um dos números com a seguinte URL:
https://pokeapi.co/api/v2/pokemon/NUMERO, substituindo oNUMEROpelos números digitados pelo usuário. O programa deverá retornar na tela os seguintes atributos da requisição recebida:id,name,sprites.front_default,height,weightetypespara cada um dos números entrados pelo usuário. Além da impressão, os dados devem ser devidamente armazenados em um novo vetor. - Utilize o vetor criado na etapa anterior para, para cada pokémon, gerar um novo arquivo
jsoncontendo o objeto resposta com os valores salvos anteriormente. O programa deve ser capaz de atualizar valores já salvos e informar do resultado de cada operação
Não esqueça de organizar o pacote devidamente através do gerenciador NPM, lembrando de incluir o project.json e excluir a pasta .node_modules antes de realizar a postagem
Todos os nomes de produtos, logotipos e marcas são propriedade de seus respectivos proprietários. Todos os nomes de empresas, produtos e serviços usados neste site são apenas para fins de identificação. O uso desses nomes, logotipos e marcas não implica endosso.

Exercícios Complementares
Implemente um pacote capaz de solicitar ao usuário uma sequência de palavras. Ao final, o programa deve salvar todas as palavras em um arquivo de texto (de preferência no formato `JSON`). No entanto, o arquivo não poderá conter palavras repetidas ou nulas.
Busque um pacote ao seu gosto no npmjs.com, utilizando e demonstrando sua utilização através da implementação do seu próprio pacote.