Aula 05 - Express.js
Apresenta a biblioteca Express.js e sua aplicação na criação de serviços Web
Exemplos de aula
Web Service

Um Web Service, ou simplesmente Serviço Web, é normalmente um software/dispositivo que tem como objetivo prover dados para outras aplicações através do protocolo http/https. Isso significa que ao invés de fornecer recursos à usuários finais, cujo a informação tem fim em si mesma, os usuários de serviços web são normalmente outras aplicações, construídas para enviar e receber dados através desses serviços.
Um serviço web pode ser construído, por exemplo, para funcionar como uma camada intermediária entre os dados armazenados e uma interface web, sendo responsável pelo tratamento e entrega dos dados a serem apresentados. Como exemplo, podemos citar outras utilizações para um webservice:
- Ler os dados de sensores e fornecer esses dados para um aplicativo mobile através da Internet;
- Verificar e fornecer um serviço de autenticação para múltiplicas aplicações dentro da rede de uma empresa;
- Enviar mensagens através de um BOT para mensageiros instantâneos;
- Receber fotos de uma aplicação desktop através da Internet, armazenando-as de modo seguro.
Um web service é geralmente considerado um tipo de API (Application Programming Interface - Interface de programação de aplicações), já que oferece um ponto de interface capaz de interagir com uma aplicação/código externo.
Atualmente podemos encontrar milhares de API disponíveis de maneira pública na Internet. Alguns exemplos:
Algumas APIs requerem autenticação. Isso significa que para realizar requisições é necessário ter algum tipo de cadastro realizado previamente. Também
TCP e IP

Estes dois protocolos de camadas mais inferiores são geralmente utilizados como base para a troca de informações na web. Enquanto o protocolo IP (Camada Internet) provê o roteamento da mensagem através dos servidores, fazendo com que os pacotes cheguem ao destino correto, o protocolo TCP (Camada Transporte) garante a integridade e a entrega de todos os pacotes. Tipicamente, requisições que chegam nessa camada acima do MTU (Maximum Transmission Unit) são divididos em vários pacotes a serem entregues.
DNS

Todo dispositivo presente em uma rede de computadores da família TCP/IP é identificado virtualmente através de um endereço IP. Esse endereço é adequado para os computadores, porém de difícil memorização para seres humanos. Por isso, cada endereço IP pode ter um ou mais nomes de domínio atrelados que facilitam sua identificação e a organização dos serviços na web.
Quando acessamos um webservice através de um nome de domínio (exemplo.com.br), é necessário obter antes o endereço de IP do servidor que irá realizar a resposta da requisição. Esse processo também é conhecido como forward lookup.
Nesse processo, o cliente realiza um requisição para o servidor de DNS local (geralmente configurado na máquina ou pelo provedor de internet). Se este servidor DNS não possuir a informação do endereço IP correspondente aquele domínio, ele informa o endereço de outro servidor (geralmente um servidor mais próximo da raiz) onde aquele endereço poderá ser encontrado. Este mesmo servidor volta a realizar uma requisição (DNS Query) até que o endereço de IP referente àquele servidor seja encontrado.
Geralmente os nomes de domínio são gerenciados por agências locais (como o NIC.br no Brasil) que padronizam, definem e comercializam os nomes de domínio. Uma outra característica importante do DNS é que os nomes são organizados de maneira hierárquica, ou seja, a cada ponto temos um agrupamento de domínios que geralmente possuem um representante centralizado. Por exemplo, no domínio professor.venson.net.br, possuimos a seguinte hierarquia:
.br- TLD (Top-Level Domain). Delegado pela IANA, administrado pelo NIC.br e comercializado no site registro.br.net.br- Subdivisão do domínio brasileiro. Responsabilidade do NIC.brvenson.net.br- Nome de domínio registrado para uma pessoa física / júridica (whois)professor.venson.net.br- Subdivisão do domínio registrado. Administrado e configurado pelo dono do domínio.
Mais informações aqui
HTTP

O Hypertext Transfer Protocol é um protocolo do tipo ou requisição/resposta. É um protocolo sem estado, o que significa que ele não pode identificar relação entre duas requisições distintas. Isso pode ser um grande problema quando trabalhamos com aplicações que exigem, por exemplo, algum tipo de autenticação. Nesses casos, é necessário que o controle de sessão seja feito pela aplicação que usa o protocolo. Uma mensagem HTTP é geralmente composto por três partes:
- Linha de requisição, onde especificamos três parâmetros:
METHOD, que define a ação da requisição (por exemplo,GETsignifica que queremos obter algum dado/recurso);HEADER, que define um dicionário contendo informações que serão de interesse de quem interpretará a mensagem (como por exemplo,User-Agentidentifica o cliente/navegador usado na requisição);BODY, o corpo da mensagem que pode conter strings especiais, texto plano, JSON, binários, etc. Esta parte da mensagem é geralmente apenas de interesse da aplicação. No caso de um website, o código-fonte da página é entregue dentro dessa área.
Por padrão, a transferência de mensagens do HTTP é realizada na porta 80, definida no protocolo TCP. É necessário, também, que a conexão com o servidor seja estabelecida de maneira previa ao envio da requisição HTTP, já que de fato é um protocolo que se encontra na camada de aplicação do modelo OSI.
Realizando conexões
Sempre que uma requisição HTTP é feita, é preciso que as camadas de rede/transporte realizem a conexão com o servidor antes de realizar qualquer requisição.
Em servidores configurados para tal, é possível especificar o cabeçalho Connection: Keep-Alive para garantir que a conexão TCP/IP não será encerrada pelo servidor após a resposta, garantindo assim que a conexão possa ser reutilizada para múltiplas requisições.
Isso
HTTPS
Mantendo suas principais características em relação à mensagem, o HTTPS se difere do HTTP por realizar a encriptação da mensagem HTTP antes da transmissão, descriptografando a mensagem após a sua chegada. Essa camada de segurança é conhecida como Transport Layer Security, ou TSL. As transações do TLS são negociadas usando um par de chaves públicas/privadas. A porta padrão utilizada pelo HTTPS é a 443.
O TSL é uma versão mais recente do Secure Sockets Layer (SSL), que também é usada para descrever a mesma camada. No entanto, é comum encontrar o termo SSL ou SSL/TLS que também possui o mesmo significado.
A troca de mensagens através da Web permite criar requisições/respostas com diferentes tipos de conteúdo (que são carregados pelo corpo da mensagem). Podemos utilizar qualquer tipo de codificação, que geralmente é informada no cabeçalho da mensagem usando a propriedade Content-Type e o tipo MIME. Esses tipos podem ser listados abaixo (mas não se resumem a estes):
- Texto plano genérico (
text/plain). Mensagens enviadas em texto plano exigem apenas conhecer a codificação de caracteres para sua interpretação. Por padrão, a codificação mais utilizada na web é aUTF-8(fonte 1, fonte 2). - Áudio (
audio/mpeg). Inclui dados de áudio ou música, no formato especificado - Vídeo (
video/mp4). Inclui dados de vídeo, no formato especificado - Imagem (
image/png). Inclui dados de imagem, no formato especificado - Binário (
application/octet-stream). Conteúdo em formato binário, sem uma codificação conhecida - PDF (
application/pdf). Conteúdo em formato pdf - HTML (
text/html). Conteúdo html, em forma de texto plano - Formulário (
multipart/form-data). Conteúdo de um formulário HTML - JSON (
application/json). Um arquivo de dados estruturado JSON
Mais sobre aqui
Biblioteca Express.js

O express é um framework utilizado em aplicações Node.js de carater minimalista que tem como objetivo oferecer um conjunto de recursos para o desenvolvimento de aplicações para a web em geral.
O framework express pode ser utilizado para construir desde servidores web com páginas estáticas até APIs (Application Programming Interfaces), oferecendo backend para outras aplicações.
O express.js pode ser instalado através de gerenciador de pacotes (como o NPM).
Site do Express.js
Dentro do seu projeto, crie um arquivo chamado index.js e inclua o seguinte código:
var express = require('express');
var app = express();
A primeira linha importa os componentes do pacote express para dentro de uma variável chamadaexpress. Já a segunda linha é responsável por iniciar uma instância do express dentro da variável app.
Em seguida, precisamos adicionar um endpoint para nossa nova aplicação, ou seja, um caminho e uma resposta válida para atender as chamadas de um cliente HTTP:
app.get('/', function (req, res) {
res.send('Olá Mundo!');
});
O código acima utiliza a função get() do express, passando como parâmetro um caminho de rota e uma função callback de resposta. Dessa forma, ao acessar o endereçolocalhost:3000/, o cliente deverá receber como corpo da resposta o Olá Mundo!, gerado pela funçãosend().
Por fim, é necessário que o script inicie um socket de rede em uma porta definida, para que nossa aplicação seja capaz de escutar requisições:
app.listen(3000, function () {
console.log('Aplicação exemplo escutando na porta 3000!');
});
A função listen() recebe como parametro uma porta escolhida e uma função callback que será executada caso tudo corra bem (e a aplicação estará finalmente aguardando por requisições).
Ao final, seu código deverá ficar assim:
var express = require('express');
var app = express();
app.get('/', function (req, res) {
res.send('Olá Mundo!');
});
app.listen(3000, function () {
console.log('Aplicação exemplo escutando na porta 3000!');
});
Para executar a aplicação, use o comando:
node index.jsA aplicação deverá retornar o conteúdo Olá mundo (por padrão, em formato HTML) ao acessar a raiz do endereço na porta 3000. Para todos os outros tipos de requisição, a aplicação retorna automaticamente o status 404 (Não foi possível encontrar o recurso).
A requisição e resposta de cada comunicação é tratada pelo express como um objeto, de modo que podem ser acessadas e manipuladas durante o processo.
Geralmente, manipulamos as requisições e respostas HTTP dentro das funções callback implementadas no fluxo de execução. Por padrão, utilizaremos os nomes de variável req eres, para nos referirmos respectivamente ao objeto de requisição e de resposta.
Valores de requisição
| Método | Descrição |
req.body | Retorna os dados do corpo da requisição. |
req.ip | Retorna o endereço IP remoto do remetente. |
req.method | Retorna o tipo de requisição HTTP. |
req.query | Retorna um objeto com a string de consulta de uma URI (ex.: o caminho/search?aprender=node+js retorna node jsquando acessamosreq.query.aprender). |
req.params | Retorna um objeto contendo os parametros definidos na rota (ex.: a rota/user/:id retorna 5 quando acessamos a rota usando o caminho /user/5). |
Uma string de consulta é uma informação inserida em uma requisição HTTP como parte de uma URL, podendo ser, por exempl, parte de um formulário HTML. Uma query string é sempre inserida ao final da URL no formato ?propriedade=valor&outra_propriedade=valor. Uma URL contendo uma query string segue este exemplo: https://exemple.org/index.html?q=laranja
Métodos de resposta
| Método | Descrição |
res.download() | Solicita que seja efetuado o download de um arquivo. |
res.end() | Termina o processo de resposta. |
res.json() | Envia uma resposta JSON. |
res.redirect() | Redireciona uma solicitação. |
res.send() | Envia uma resposta de vários tipos. |
res.sendFile() | Envia um arquivo como um fluxo de octeto. |
res.sendStatus() | Configura o código do status de resposta e envia a sua representação em sequência de caracteres como o corpo de resposta. |
Códigos de resposta
Outro atributo importante a ser usado em um objeto de resposta que permite definir o status da mensagem é o res.status(numero). O número da resposta é uma informação muito importante para o cliente e pode ser configurado antes do envio de uma mensagem, como no exemplo:
res.status(404).send("Página não encontrada")
Para o protocolo HTTP, existe uma tabela padronizada de códigos de estados que deve ser utilizada para informar o cliente do tipo de resposta dada. Essa informação pode ser útil, por exemplo, para identificar que uma requisição falhou por falta de informações antes mesmo que o cliente precise ler o corpo da resposta.
Para mais código de estados, visite este site.

Eventualmente em nossa aplicação temos a necessidade de adicionar funções que alteram os objetos de requisição e resposta. Isso pode ser utilizado, por exemplo, para adicionar autenticação ou desviar o fluxo de determinados tipos de requisições. Essas funções intermediárias são chamadas de middlewares.
O uso de um middleware é implementado de acordo com o seguinte exemplo:
const app = express()
app.use(function(req, res, next) {
console.log('Relógio:', Date.now())
next()
})
No exemplo, utilizamos a função use(), que recebe uma função contendo a requisição (req), a resposta (res), e a próxima função de middleware (next).
Ao finalizar a execução da função de middleware, deve-se sempre adicionar o comandonext(), caso contrário a requisição será interrompida.
Podemos também adicionar um caminho específico para a montagem do middleware, como no exemplo:
app.use('/relogio', function(req, res, next) {
console.log('Relógio:', Date.now())
next()
})
Dessa forma, definimos que a função callback implementada será executada apenas em requisições realizadas para o caminho /relogio.
Também é possível definir uma lista com funções middlewares, como no exemplo:
app.use('/relogio', [funcao01, funcao02, funcao03])
O express permite funções middlewares de:
- Aplicação (
app.useouapp.METODO) - Roteamento (
router.use) - Erro (
app.use(err, req, res, next)) - Nativo (
express.static,express.json,express.urlencoded) - Terceiros (
bodyparser,cookieparser)
A configuração de rotas refere-se à configuração de endpoints e suas respectivas respostas. A definição de uma nova rota segue a seguinte estrutura:
app.METODO(CAMINHO, HANDLER)
Onde:
- app é a instância de express
- METODO é o tipo de solicitação HTTP (GET, POST, PUT...)
- CAMINHO é o endereço no servidor
- HANDLER é a função executada
É possível configurar diferentes métodos para diferentes caminhos:
app.get('/', function (req, res) {
res.send('Olá mundo!');
})
app.post('/', function (req, res) {
res.send('POST RESULT');
})
O express suporta diversos métodos para atender os diferentes tipos de requisição HTTP (get,post, put, head, delete...). Além disso, há também o método all() que atende a todos as requisições independente do método HTTP utilizado.
É possível utilizar padrões de sequência para oferecer caminhos de rota que atendam critérios especiais, como:
// Aceita bana, banana, ba234na, bababana...
app.get('/ba*na', function(req, res) {
res.end()
})
// Aceita bana e banana
app.get('/ba(na)?na', function(req, res) {
res.end()
})
// Aceita bana, baana, baaana...
app.get('/ba+na', function(req, res) {
res.end()
})
// Exemplo de expressão regular (aceita butterfly, dragonfly...)
app.get(/.*fly$/, function(req, res) {
res.send('/.*fly$/')
})
Para fornecer arquivos estáticos através do express, podemos utilizar uma função middleware chamada express.static(). Para utilizar essa função, vamos carrega-la em nossa aplicação através da função use():
app.use(express.static('public'))
A string public refere-se ao nome da pasta na raiz do projeto que corresponde aos arquivos que serão acessíveis estaticamente. Dessa forma, é possível por exemplo acessar o arquivo /public/img/logo.png usando a URI http://localhost:3000/img/logo.png
Pode-se usar múltiplicos diretorios estáticos, declarando diversas vezes o exemplo anterior:
app.use(express.static('img'))
app.use(express.static('css'))
app.use(express.static('js'))
Também é possível passar como parametro o caminho de montagem, para acesso ao recurso estático:
app.use('/static', express.static('public'))
Dessa forma, a URI utilizada para acessar o mesmo arquivo no exemplo anterior seriahttp://localhost:3000/static/img/logo.png, mesmo que o caminho virtualstatic não exista no sistema de arquivos.
Um redirecionamento pode ser informado na resposta ao cliente. Repare que isso não entrega automaticamente o conteúdo do endereço redirecionado, apenas informa ao cliente para que realize outra requisição em um novo endereço.
app.get('/', function(req, res, next) {
res.redirect('manutencao.html')
})
Este redirecionamento é registrado nos clientes como temporário (código 302). Se você quer definir um redirecionamento definitivo, utilize o status 301, usando o comandosendStatus(301):
res.redirect(301, 'outro.html');
O express não faz o parse automático de requisições HTTP, mas podemos configurá-lo para tratar as informações recebidas através das requisições, sejam elas objetos JSON ou informação de formulário. Para isso, precisamos utilizar os seguintes middlewares na aplicação:
app.use(express.urlencoded({extended: true}));
app.use(express.json());
Lembre-se de que isso deve ser feito ANTES da declaração do middleware/rota que irá ler o corpo. A leitura do corpo da mensagem pode ser feito com req.body
Você também pode fazer isso diretamente através da biblioteca body-parser:
var bodyParser = require('body-parser')
var jsonParser = bodyParser.json()
var urlencodedParser = bodyParser.urlencoded({ extended: false })
app.post('/usuarios', urlencodedParser, function (req, res) {
//req.body.usuario
})
Outras Ferramentas

O Insomnia é um cliente para APIs open source capaz de gerar, organizar e documentar requisições REST, SOAP, GraphQL e GRPC.
Esta ferramenta é extramemente útil para realizar os testes de requisições para uma API sem a necessidade de gerar um cliente com essa finalidade.
Site Insominia
Mão na Massa
Implemente uma aplicação que seja capaz de receber, através de query strings, uma palavra chave. O programa deverá abrir este arquivo json, e retornar a resposta com o objeto ao usuário. A pesquisa deve permitir inserir o nome de um personagem e retornar a casa ao qual ele pertence.
Implemente uma aplicação utilizando Node e Express que seja capaz de gerar uma lista de compras de forma aleatória. A lista deverá conter no mínimo 1 e no máximo 15 itens, porém o usuário pode passar através de query strings o número exato de items que ele deseja receber na lista. Caso a query string seja inválida (número maior que 15 ou menor que 1 ou não seja um número), o programa deve retornar uma mensagem de erro com o status 400
Implemente também um midleware que seja capaz de salvar em um arquivo de texto todas as requisições e suas respectivas query strings de entrada.
Exercícios Complementares
Implemente uma aplicação que possua dois métodos:
- um do tipo GET, responsável por retornar uma lista com nome, email e telefone de pessoas.
- um do tipo POST, responsável por inserir nesta lista um objeto
A lista deverá ser armazenada utilizando um método de persistência como repositório do pacoteLevelDB.
Dica: Utilize o pacote body-parser para receber os objetos e um formulário HTML para enviar os dados através do POST.
Crie três páginas HTML, com seu respectivo CSS:
- O primeiro arquivo deverá se chamar
login.html, e deverá conter um formulário HTML contendo campos de entrada deusuárioesenha - O segundo arquivo deverá se chamar
sucesso.html, e deverá conter uma tela com uma mensagem de sucesso no login. - O terceiro arquivo deverá se chamar
404.html, e deverá exibir uma mensagem de erro (recurso indisponível)
Implemente uma aplicação usando nodejs de realizar a validação do login:
- O validador deverá ser implementado no lado do servidor e será responsável por validar apenas o usuário
rootcom a senhaunesc2019, enviando ao usuário a páginasucesso.html. - Caso a usuário ou senha não sejam validados, a página deverá retornar à página
login.html, apresentando uma mensagem de erro (que deverá ser tratada por um script no lado do cliente) - Para qualquer URI desconhecida, a aplicação deverá redirecionar para a página
404.html. - Escreva um middleware que seja executado antes do
express.statice impeça um usuário não logado de acessar a páginasucesso.html. - Utilize um botão de deslogar na página
sucesso.html.

Implemente um formulário HTML capaz de inserir produtos em uma lista e uma aplicação usando nodejs capaz de receber estes itens e salvá-los em um arquivo de texto. O formulário HTML também deve ser capaz de mostrar os itens armazenados no servidor. Utilize o método GET para receber dados do formulário fornecer os dados a serem inseridos.
Implemente uma aplicação em nodejs que retorne uma imagem armazenada no servidor caso o caminho indicado corresponda ao nome da imagem (ex.: http://localhost:3000/imagens/florestadeve retornar um arquivo chamado floresta.jpg para download).