Aula 09 - REST
Uma visão geral sobre a arquitetura REST e sua aplicação com Express.js
REST

A Web que conhecemos é recheada de recursos. Estes recursos podem ser entendidos como basicamente qualquer coisa que possa ser identificada e endereçada. Dessa forma, é muito comum atualmente que os dados que acessamos ao navegar pela Web possuam uma estrutura sólida que permita que diferentes serviços possam se comunicar usando um padrão comum.
Uma das arquiteturas mais utilizadas na web para criação de APIs que permitem a troca informações entre serviços é o padrão REST (Representational State Transfer). Essa arquitetura define um conjunto de restrições na representação e operação de dados que são utilizadas na criação de serviços web.
REST é um acrônimo para Representational StateTransfer.
Site com documentação para o REST
A arquitetura REST segue 6 princípios:
- Cliente/Servidor - separa o armazenamento de dados da interface de usuário
- Stateless - toda requisição do cliente precisa conter toda informação necessária.
- Cacheable - As respostas à uma requisição podem conter informações sobre a reutilização de uma resposta
- Interface Uniforme - aplica o conceito de generalização de engenharia de software, padronizando o acesso aos dados da aplicação
- Sistema de Camadas - permite a composição hierarquica de acesso aos dados
- Código sob-demanda - permite a criação de clientes que podem requisitar informações e extende-las sem a necessidade de alterar a arquitetura do servidor.
A abstração chave na arquitetura REST é o resource (recurso). Toda informação que pode ser nomeada pode ser um resource na implementação REST. Por exemplo:
- Usuário
- Foto
- Time de Futebol
- Jogador de Futebol
- Pokémon
- Treinador Pokémon
Uma resource pode ser identificado de maneira hierarquica. Dessa forma, nascem os identificadores chamados de URI (Unified Resource Identifier)
/usuarios
/usuarios/fotos
/time/jogador
/treinador
/treinador/pokemon/25 Por boa prática, utilizamos algumas regras para declarar resources:
Use substantivos para recursos e verbos para ações
Utilize nomes substantivos e verbos adequados para cada situação, colocando no substantivos no plural quando necessário
Document
Representa um objeto singular:
http://localhost/gerenciamento http://localhost/adminCollection
Representa uma coleção de objetos gerenciada pelo servidor:
http://localhost/usuarios http://localhost/labs/07/computadoresStore
Representa uma coleção de objetos gerenciada pelo cliente:
http://localhost/usuario/200/carrinho http://localhost/usuario/200/playlistController
Representa uma função adicional aplicada aos dados:
http://localhost/hotel/200/check-in http://localhost/temporada/01/startUse barra para relações de hierarquia
Para representar relações de hierarquia de um recurso com outro (ex.: Usuário possui fotos), utilize a barra:
http://localhost/bancos/contas/400ANão use barras no final de uma URI
A barra no final de uma URI não adiciona nenhum valor semântico ao endereço e pode causar confusão.
http://localhost/usuarios/ http://localhost/usuarios # MelhorUse hífens (-) para aprimorar a leitura de uma URI
Utilize hífens para separar palavras quando possível, pois são mais fáceis de ler quando inseridos dentro de uma URI
http://localhost/carrosDeAluguel http://localhost/carros-de-aluguel # MelhorEvite o uso de traço baixo (_)
O traço baixo (underline), pode ser facilmente confundido. Use hífens.
http://localhost/carros_de_aluguel http://localhost/carros-de-aluguel # MelhorEvite o uso de letras maiúsculas
Procure ser consistente nos caracteres utilizados
http://localhost/Usuarios http://localhost/usuarios # MelhorNão adicione a extensão requerida na URI da requisição
O HTTP já possui um cabeçalho para definir o tipo de dado requisitado chamadoContent-Type
http://localhost/usuarios.json http://localhost/usuarios # MelhorUse Query String para filtrar coleções
As query strings são melhor utilizadas como filtros para a consulta a um determinado recurso
http://localhost/paises?continente=America http://localhost/paises?continente=Africa&limite=5Nunca use o nome das funções CRUD na URI
O protocolo HTTP já possui verbos em seu protocolo para definir estes tipos de requisição (GET, POST, DELETE...)
http://localhost/usuarios/GET http://localhost/usuarios/Adicionar Para mapearmos a implementação de um CRUD (Create, Read,UUpdate, Delete) usando a arquitetura REST, iremos utilizar os métodos descritos pelo protocolo HTTP como referência. Para isso, usaremos:
GET, para consultar resourcesPOST, para adicionar resourcesPUT, para atualizar resourcesDELETE, para deletar resources
Adicionalmente, podemos utilizar:
PATCH, para atualizar partes de um resourcePUT, para adicionar resources
O método GET tem a finalidade de retornar dados em nossa API. Podemos consultar um conjunto de dados (por exemplo, uma collection). Não é necessário passar nada no corpo da mensagem.
GET "/usuarios"
//RETORNO
[
{ "_id": 1, "login": "prezi", "senha": "abc123"},
{ "_id": 2, "login": "delta", "senha": "!@#$DFSER"},
{ "_id": 3, "login": "alfa", "senha": "USER123$"},
]
Ou um único recurso:
//REQUISIÇÃO
GET "/usuarios/3" // usuarios/:id
//RETORNO
{ "_id": 3, "login": "alfa", "senha": "USER123$"}
O método POST pode ser utilizado para inserir novos objetos em uma coleção. É necessário passar no corpo da mensagem o objeto completo a ser inserido. O retorno pode ser o próprio objeto enviado.
//REQUISIÇÃO
POST /usuarios
//BODY
{ "login": "beta", "senha": "betinho123"}
O método PUT será utilizado para atualizar um recurso ou coleção. É necessário passar no corpo da mensagem um objeto completo a ser atualizado. O retorno, em caso de sucesso, pode ser o próprio objeto enviado.
//REQUISIÇÃO
PUT /usuarios/3
//BODY
{ "login": "diddy", "senha": "QWERTY"}
Adicionalmente, o método PUT também pode ser utilizado para inserir novos objetos, dado que caso o usuário de id 3 não exista, ele será criado.
O método DELETE é utilizado para deletar recursos. Não é necessário passar nada no corpo. O retorno pode ser, em caso de sucesso, o próprio objeto deletado.
//REQUSIÇÃO
DELETE /usuarios/5000
O método PATCH é utilizado para realizar alterações em um recurso, geralmente em parte dele. O retorno geralmente é o recurso atualizado.
//REQUISIÇÃO
PATCH /usuarios/5000
//BODY
{ "senha": "CASACO1992" }
Aplicação Express
Utilizando o objeto javascript abaixo, podemos realizar a implementação de um CRUD básico para ilustrar a arquitetura REST que entrega dados no formato JSON.
var dados = {
"personagens": [
{
"nome": "Willas",
"raca": "humano",
"idade": 43
},
{
"nome": "Ernal",
"raca": "elfo",
"idade": 125
},
{
"nome": "Villey",
"raca": "humano",
"idade": 27
},
{
"nome": "Furi",
"raca": "anão",
"idade": 50
},
]
}
Para consultar todos os personagens:
// GET "/personagens"
router.get('/', function(req, res){
res.json(dados.personagens)
})
Para consultar o personagem de nome ``Ernal``:
// GET /personagens/1
router.get('/:id', function(req, res){
res.json(dados.personagens[req.params.id])
})
Para consultar apenas personagens humanos:
// GET "/personagens?raca=humano"
router.get('/', function(req, res){
var filtered = dados.personagens.filter(function(element){
return element.raca == req.query.raca
})
})
Para adicionar um novo personagem:
// POST "/personagens" BODY { "nome": "Eragon", "raca": "humano", "idade": 16}
router.post('/', function(req, res){
var personagem = req.body
dados.personagens.push(personagem)
res.json(personagem)
})
Para modificar um personagem:
// PUT "/personagens/1" BODY { "raca": "humano", "idade": 16 }
router.put('/:id', function(req, res){
var personagem = req.body
if(dados.personagens[req.params.id]){
dados.personagens[req.params.id] = personagem
}
res.json(dados.personagens[req.params.id])
})
Para deletar um personagem:
// DELETE "/personagens/1"
router.delete('/:id', function(req, res){
var deleted = dados.personagens.splice(req.params.id, 1)
res.json(deleted)
})
Mão na Massa
Implemente uma API REST capaz de responder as solicitações de um CRUD para este conjunto de dados. Utilize um arquivo JSON para armazenar e manipular os dados da API. Crie rotas para cada um dos resources encontrados no arquivo JSON.