21 de junho de 2022 • 9 min de leitura
API Restful com Node.js, Express e Typescript
Neste post estarei abordando os conceitos básicos de API, REST, Node.js, Typescript, além de outros pontos relevantes para criação de uma API.
O que é API?
API é um acrônimo para Application Programming Interface
ou Interface de Programacao de Aplicativos
.
É um conjunto de especificações que definem de que forma as aplicações irao se comunicar.
Com a API você tem uma interface para que um sistema se comunique com outro sistema, compartilhando suas ações e ferramentas. A comunicação é feita através de vários códigos, definindo comportamentos específicos.
As APIs são muito úteis e tem diversos benefícios, além disso proporciona uma troca de informações muito segura, já que somente o proprietário da aplicação define quais informações estarão disponíveis. Você pode e deve utilizar uma API quando necessário, mas sempre visando pontos importantes de segurança.
É importante utilizar SSL nas conexões das APIS, assim toda a comunicação e dados enviados pelas APIS serão transportados criptografados pelo HTTPS. A autenticação também é importante para proteger de acessos indevidos a informação. Um exemplo são os tokens, que são validados como se fossem uma senha, pois são identificadores únicos que são enviados juntos das chamadas aos endpoints das APIs.
Para levar as informações de um lado para o outro, geralmente é utilizado o JSON, muito utilizado para retornar os dados das APIS baseadas em web. Além disso, esse conceito ocupa pouco espaço e é fácil de transportar via rede.
Algo fundamental em uma API é uma documentação, para orientar os desenvolvedores das outras aplicações que irão consumir as informações dessa API. Um exemplo é a API dos correios.
O que é REST?
Representation State Transfer ou Transferencia Representacional de Estado.
Até um tempo atrás, a maioria das aplicações eram criadas com base na arquitetura MVC (model, view e controller). Esse modelo reúne toda a estrutura (backend e frontend) em uma única aplicação, onde o servidor fica encarregado de receber as requisições, processar, gerar um HTML e devolver esse HTML contendo a resposta para o cliente.
A arquitetura REST separa o backend do frontend. Nesse caso, o backend depois de receber e processar as requisições, ele responde ao cliente as informações de forma estruturada (normalmente no padrão JSON).
Com isso, o mesmo backend pode atender diversos frontends, podendo ser web, mobile, ou até outras aplicações backends.
Arquitetura REST
O REST é um modelo de arquitetura com algumas características que podemos citar:
- Client-server: separar as responsabilidades.
- Stateless: o servidor nao armazena estado ou sessão.
- Cache: suporte para uso de cache na API.
- Interface Uniforme: uma espécie de contrato entre o servidor e o cliente, que define os recursos a serem consumidos, com método (HTTP), servidor, recurso (entidade) e parâmetro. Também define a estrutura de dados, como JSON por exemplo.
- Camadas: Balanceamento de cargas, segurança, etc.
- Código sob demanda: permite que as funcionalidades do cliente sejam estendidas no forma de mini aplicativos.
Funcionamento básico
- A requisição é feita por um cliente, que pode ser um browser, um app mobile, etc.
- Resposta retornada através de uma estrutura de dados (JSON: Javascript Object Notation).
- Cliente recebe a resposta e processa o resultado.
- As rotas utilizam métodos HTTP, sendo compostas por: método, servidor, recurso (entidade) e parâmetros, ou seja, a rota é o endereço completo da requisição:
GET https://aluiziodeveloper.com.br/books
POST https://aluiziodeveloper.com.br/books
PUT https://aluiziodeveloper.com.br/books/1
DELETE https://aluiziodeveloper.com.br/books/1
Conteúdo da requisição
Route Params e Query Params
Conteúdo da requisição: GET https://aluiziodeveloper.com.br/books/1/authors?page=2
.
Podemos observar nessa requisição o seguinte conteúdo: método http (GET), servidor, recurso (books), route params e query params. Normalmente os query params são nomeados, como o page=2
. Já os routes params são representados apenas pelo valor.
Request Body
Outra forma de enviar conteúdo em requisições é através de request body ou corpo da requisição, porém normalmente com os métodos POST, PATCH e PUT.
Exemplo de criação de um livro: POST https://aluiziodeveloper.com.br/books
. No caso, os dados do JSON abaixo serão enviados no corpo da requisição.
{
"book": {
"title": "Design Patterns",
"publisher": "Bookman",
"category": ["Design Patterns", "Techonology", "Project"],
"author": {
"name": "Erich Gamma"
}
}
}
Benefícios da Arquitetura REST
- Multiplos clientes (frontend) para usufruir de um mesmo backend.
- Protocolo de comunicação padronizado, sendo a mesma estrutura para web, mobile, etc.
- Comunicação com serviços externos.
- A padronização com o JSON faz com que qualquer tecnologia frontend e mobile (Angular, Ionic, ReactJS, React Native, Vue.js) consiga consumir os dados do backend:
{
"book": {
"id": 10,
"title": "Design Patterns",
"publisher": "Bookman",
"category": ["Design Patterns", "Techonology", "Project"],
"author": {
"id": 14,
"name": "Erich Gamma"
}
}
}
Headers HTTP
Headers: campo para envio de informações adicionais (normalmente formatação ou autorização) que não tem relação com os dados em si: Authorization, Content Type, Accept, etc.
HTTP Codes (status da resposta):
- 1xx: Informativo
- 2xx: Sucesso (200 - Success, 201 - Created, 204 - No Content)
- 3xx: Redirecionamento (301 - Moved permanently, 302 - Moved)
- 4xx: erros do cliente (400 - Bad request, 401 - Unauthorized, 404 - Not found)
- 5xx: erros internos do servidor
O que é o Node.js
Node.js é um runtime JavaScript desenvolvido com o Chrome's V8 JavaScript engine.
É uma plataforma open-source que permite a execução da liguagem Javascript do lado do servidor.
Como um ambiente de execução JavaScript assíncrono orientado a eventos, o Node.js é projetado para desenvolvimento de aplicações escaláveis de rede.
O Node.js é construído com as novas versões do V8, mantendo-se em dia com as últimas atualizações desta engine.
Isso garante que as novas funcionalidades da especificação JavaScript ECMA-262 são trazidas para os desenvolvedores Node.js em tempo hábil, assim como as melhorias contínuas de performance e estabilidade.
Alguns recursos do Node.js
- Módulos próprios: http, fs, buffer, dns, etc.
- Non-blocking I/O: chamar diversas funções sem que uma função fique bloqueada aguardando a conclusao da execução de alguma outra função para que possa seguir.
- Usado para construção de rotas, integrações com serviços externos (serviços de pagamentos, acesso a APIs externas, banco de dados, etc).
- No Node.js não lidamos com eventos do usuário final (alert, eventos de botões, mouseover, etc).
- Podemos comparar aplicações Node com qualquer aplicação construída com linguagens como PHP, Ruby, Python, Go, que se aplicam ao backend.
O que é o NPM?
Tanto o NPM quanto o Yarn, são ferramentas para instalação de bibliotecas de terceiros em nossas aplicações Node.js (gerenciam nossas dependências). O NPM já vem junto com o Node.js. O Yarn deve ser instalado separadamente.
Principais comandos com o npm:
npm init
- iniciar um projeto Node.js criando o arquivo package.json
.
npm install
, i [module] - instalar o módulo específico. Se o módulo não for informado instalará todos os pacotes contidos no arquivo package.json
.
npm ls
- listar os módulos instalados no projeto.
npm ls --depth 0
- listar os módulos instalados no projeto, sem a árvore de dependências.
npm outdated
- listar os módulos que estão desatualizados.
npm update
, up [module] - atualizar o módulo específico. Se o modulo não for informado atualizará todos.
npm uninstall
, un [module] - desistalar um módulo do projeto.
Criando um API Restful com Node.js e ExpressJS
O ExpressJS será usado como base de criação das rotas, por ser um micro framework bem simples e prático, o que facilita o início do aprendizado.
Instalando o Express
Apesar do Node.js possuir o módulo http
, a prática comum no mercado é o uso do micro framework Express
, que é responsável por gerenciar as rotas e os middlewares da nossa aplicação.
Vamos criar um projeto bem simples, ainda sem Typescript, apenas para facilitar o entendimento dos conceitos que veremos na sequência.
npm init
npm init -y
Esse comando criará o arquivo package.json
, que é responsável por armazenar todas as informações relevantes do projeto, tais como a lista de dependências, os scripts para interação com o projeto (instalar, executar, fazer o deploy, etc), o nome e email do autor do projeto, etc.
Com o projeto criado, vamos instalar o Express.
npm i express
Observe que também foi criada a pasta
node_modules
, que é responsável por armazenar todas as dependências do nosso aplicativo.
Abrir o projeto no VS Code.
Para vermos o nosso primeiro Olá Dev!
, iniciamos fazendo a importação do express para dentro de uma constante e a partir podemos criar uma variável app para inicializar o express.
Arquivo src/index.js
:
const express = require('express')
const app = express()
Para que uma aplicação cliente consiga acessar o conteúdo da nossa aplicação, precisamos disponilizar um endereço composto por http://server:port, pois pode ser necessário disponibilizar mais de uma aplicação na mesma máquina, por isso precisamos especificar em qual porta a nossa aplicação irá responder.
A recomendação é para utilizar portas acima da 1024
, pois várias das portas inferiores a este número já são reservadas para outros serviços e podem estar em uso.
Utilizarei a porta 3000, ficando o endereço composto por: http://localhost:3000.
Só essa configuração ainda não nos dá uma resposta legal se tentarmos acessar pelo browser, por exemplo.
Então para resolvermos isso faremos uso do express, que consegue verificar as requisições que chegam na aplicação e tratá-las.
Através da variável app
temos acesso a todos os métodos disponibilizados pelo express para que possamos tratar as rotas da aplicação.
Imagine que a nossa aplicação irá disponibilizar um recurso chamado projects
para que os clientes possam acessar informações de projetos.
Nesse caso, a url completa para acessar esse recurso será: http://localhost:3000/projects
.
Para implementarmos isso, faremos uso do método get
do express através da variável app
. Esse método recebe dois parâmetros, o primeiro é o nome do recurso a ser consumido e o segundo parâmetro é uma função para tratar essa solicitação.
A função, por sua vez, também recebe dois parâmetros (request
e response
) e precisa retornar uma resposta para o cliente que solicitou os dados.
Toda resposta deve ser realizada usando parâmetro response
, pois ele que contém tudo que precisamos para retornar algo ao solicitante.
Já o parâmetro request
traz todas as informações enviadas pelo cliente, como por exemplo, quais parâmetros foram enviados, qual é a rota, quais dados foram enviados no corpo da requisição, etc.
const express = require('express')
const app = express()
app.get('/', (request, response) => {
return response.send('Olá Dev!')
})
app.listen(3000)
Verificar o funcionamento do app:
node src/index.js
Podemos acessar pelo browser: http://localhost:3000/
.
Normalmente uma API retorna um JSON estruturado para que a aplicação cliente pegue esses dados e faça o uso de forma que bem entender.
Vamos então alterar o retorno da nossa rota para que seja retornado um JSON. Lembrando que um JSON pode retornar ou um array ou um objeto.
const express = require('express')
const app = express()
app.get('/', (request, response) => {
return response.json({ message: 'Olá Dev!' })
})
app.listen(3000)
Agora vamos configurar uma mensagem para ser exibida no terminal para que possamos saber se o servidor subiu normalmente ou se há algo errado.
O método listen
pode receber uma função como segundo parâmetro e essa função é executada automaticamente no momento em que o servidor entrar em execução.
Arquivo src/index.js
:
const express = require('express')
const app = express()
app.get('/', (request, response) => {
return response.json({ message: 'Olá Dev!' })
})
app.listen(3000, () => {
console.log('Server started on port 3000! 🏆')
})
Se tentarmos acessar o app pelo browser novamente, a informação não estará atualizada, porque o Node não faz o "live reload" automaticamente. Cancele com CTRL+C e execute novamente.
Aprendemos o básico até aqui com Node, criando um servidor HTTP com o Express, responsável por ouvir requisições de clientes na porta 3000 e enviar a devida resposta usando o JSON.