Aula 08 - JSON e Roteamento
Apresenta os detalhes do formato JSON e do roteamento no Express.js
Exemplos de aula
JSON
O JSON (Javascript Object Notation) é um formato de troca de dados em modo texto baseado na notação de objetos do javascript. Ele é utilizado atualmente em muitas APIs na Web para fornecer e receber dados em um formato padronizado e de fácil desconstrução.
- Significa Java Script ObjectNotation;
- É um formato para troca de dados;
- Independente de linguagem de programação;
- Sintaxe simples e textual;
{
"usuarios": {
"john": {
"email": "john@matrix.com",
"senha": "12345"
},
"mary": {
"email": "m.mary@bol.com.br",
"senha": "abc123",
"admin": true
}
}
}
O formato JSON é submetido às seguintes regras:
- Os dados são encapsulados em pares chave/valor;
- Os dados são separados por
,(virgula); - Um par chave/valor é encapsulado por
(chaves); - Vetores são encapsulados por
[ ](conchetes).
Um dado vazio no formato JSON é dado pela seguinte sintaxe:
{}Um par de chave/valor pode ser descrito como o seguinte exemplo:
{ "usuarios" : "john e mary" }Podemos substituir ainda um valor por outro par chave/valor:
{
"usuarios": {
"john": {
"email": "john@matrix.com",
"senha": "12345"
},
"mary": {
"email": "m.mary@bol.com.br",
"senha": "abc123",
"admin": true
}
}
}
Dessa forma, obtemos um objeto chamado usuarios que contém dois outros objetos (john e mary), que por sua vez possuem outros objetos.
Repare que apenas mary possui uma chave chamada admin. Isso é possível pois o formato de dados do JSON é semi-estruturado, ou seja, permite a estruturação dos dados sem uma estrutura formal, geralmente associada com tabelas de dados.
O JSON suporta os seguintes tipos de dados:
- Strings (ex.:
"cem"); - Números (ex.:
100,100.0,1.0E+2,1E+2); - Objeto (ex:
{ "cem" : 100 }um objeto JSON ); - Vetor (ex:
[100, 100.1, "cem"]); - Booleano (ex.:
trueoufalse); - Nulo (ex.:
null).
Valores que não são considerados tipos de dados no JSON:
- Funções;
- Datas;
- Indefinido (
undefined).
Enquanto o JavaScript permite a criação de chaves para objetos sem o uso de aspas duplas, a chave de um objeto JSON precisa estar sempre encapsulada dessa forma.
{ nome: "Rivelino" } ERRADO!!!
{ "nome": "Rivelino"} CORRETO
O JavaScript possui dois métodos simples para a conversão de objetos em texto JSON e vice-versa:
JSON.parse(jsonString) // Converte uma string JSON em objeto javascript
JSON.stringify(object) // Converte um objeto javascript em uma string JSON
Assim que usamos o método parse() para converter uma string JSON em um objeto javascript, podemos acessar seus dados de maneira habitual, encadeando as propriedades e os índices necessários:
object.usuarios.john.senha // Dot Notation
object["usuarios"]["john"]["senha"] // Bracket notation
Repare que não seria possível acessar um atributo com espacos (ex.:primeiro nome) usando a primeira sintaxe (dot notation).
Outro comportamento importante ao trabalhar com objetos javascript é que podemos atualizar o valor de propriedades mesmo inexistentes, que geram novos membros do objeto.
object["usuarios"]["john"]["senha"] = "senhaforte123"
object.usuarios.john.logado = false
Por fim, quando temos um objeto javascript, também podemos criar e acessar funções como valores para um objeto:
var object = {
"primeiro_nome": "Ramon",
"sobrenome": "Venson"
"nome_completo": function(){
return this.primeiro_nome + ' ' + this.sobrenome
}
object.nome_completo() // Retorna string "Ramon Venson"
Porém, lembre-se de que funções não são aceitas pelo JSON e não serão convertidas quando usamos o método stringify()
Ao usar o método JSON.stringify(), convertemos um objeto javascript para string. Neste caso, podemos também passar como parâmetro uma função replacer para criar máscaras para nosso objeto:
var mascara = function(chave, valor){
if(chave == "senha"){
return "*****"
} else { return valor }
}
objeto = {
usuario: "root",
senha: "123456"
}
JSON.stringify(objeto, mascara)
// Retorna { "usuario": "root", "senha": "*****"}
Para responder qualquer requisição no formato JSON, utilizamos a função json(), presente no objeto de requisição com um objeto ou vetor.
app.get('/', function(req, res){
var objeto = { usuario: "Ramon", senha: "12345"}
res.json(objeto)
})
Ao usar o método json() ao invés do send(), podemos definir mascaras personalizadas como emJSON.stringify() usando o método set() do express.
app.set('json replacer', function(chave, valor){
if(chave == "senha"){
return "*****"
} else {
return valor
}
})
app.get('/', function(req, res){
var objeto = { usuario: "Ramon", senha: "12345"}
res.json(objeto)
})
Rotas
O Router é um dos recursos apresentados pelo express. Com a utilização desse middleware, podemos agrupar os manipuladores de rota para partes específicas da nossa API. Dessa forma, é possível definir rotas hierarquicamente e de maneira organizada.
Por boas práticas, criaremos uma nova pasta em nossa aplicação chamada ``routes``. Essa pasta irá conter arquivos individuais com cada um dos recursos da nossa aplicação. Adicionalmente podemos utilizar pastas para cada conjunto de recursos.
Em seguida, dentro da pasta, criaremos um arquivo javascript onde definiremos a rota de um de nossos resources.
Nos exemplos a seguir, usaremos como base um resource chamado usuarios.js.
Criando as rotas
Primeiro, vamos definir inicializar uma instância middleware router:
const express = require('express')
const router = express.Router()
Em seguida, faremos a configuração das rotas da nossa aplicação:
router.get('/', function(req, res){
var usuarios = getUsuarios()
res.json(usuarios)
})
router.get('/:id', function(req, res){
var id = req.params.id
var usuarios = getUsuario(id)
res.json(usuarios)
})
router.post('/', function(req, res){
var usuario = req.body
var resultado = saveUsuario(usuario)
res.send(resultado)
})
router.put('/:id', function(req, res){
var id = req.params.id
var usuario = req.body
var resultado = saveUsuario(usuario, id)
res.send(resultado)
})
router.delete('/:id', function(req, res){
var id = req.params.id
var resultado = deleteUsuario(id)
res.send(resultado)
})
Exportando as rotas
Ao final do arquivo, iremos permitir a importação deste em outros locais de nossa aplicação, usando o comando:
module.exports = router
Isso faz com que o javascript identifique quais parâmetros desejamos importar do arquivousuarios.js. Nesse caso, estamos exportando todas as funções CRUD criadas para o recurso usuário
Importando as rotas
Com nosso arquivo de rotas para usuarios.js criado, vamos chamá-lo no script principal:
const rotas_usuario = require('./rotas/usuarios')
app.use('/usuarios', rotas_usuario)
Repare que na função require() utilizamos no caminho o . (ponto) para indicar a pasta atual. Não há necessidade de colocar a extensão do arquivo (.js).
Na função use(), utilizamos o caminho com o qual queremos encadear as rotas que acabamos de configurar. Dessa forma, podemos organizar outros resources simplesmente adicionando-os através de uma importação no arquivo principal.
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
Para testar a aplicação durante o desenvolvimento, é necessário reiniciar a execução do node.js.
Vamos utilizar um módulo para executar nossa aplicação que é capaz de monitorar as alterações do código e reiniciar nosso servidor automaticamente, de modo transparente.
Para isso, basta realizar a instalação do ``nodemon`` através do comando:
npm install nodemon --saveE atualizar o arquivo package.json com o script start:
{
"name": "express-full-api",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "nodemon index.js" <-- INSIRA ESTA LINHA
},
"author" : "" ,
"license" : "ISC" ,
"dependencies": {
"cors" : "^2.8.5" ,
"express" : "^4.17.1" ,
"nodemon" : "^1.19.2"
}
}
Lembre-se que index.jsé o nome geralmente dado ao script principal da aplicação. Modifique caso utilize outro nome.
Cross-Origin Resource Sharing (Compartilhamento de recursos com origens diferentes) é um mecanismo implementado pela maioria dos navegadores que exige cabeçalhos adicionais HTTP para permitir o acesso à recursos de um domínio externo. Dessa forma, um cliente não poderá realizar requisições para um domínio diferente do seu.
Para habilitar o uso da API para diferentes domínios nos navegadores, precisamos configurar o cabeçalho das respostas do express com os mecanismos do CORS.
Isso pode ser feito usando o módulo cors. Primeiro realize a instalação usando o comando:
npm install cors --saveEm seguida, configure o middleware para ser utilizado pelo express:
const express = require('express')
const app = express()
const cors = require('cors')
app.use(cors())
Mão na Massa
Implemente um rota GET para o express chamada /gerador que retorna uma string como no exemplo:
Cássio Ramos é um futebolista brasileiro de 32 anos que atua como goleiro. Atualmente defende o Corinthians.A informação gerada deverá conter os seguintes requisitos:
- Nome e Sobrenome (aleatórios)
- Idade (17-40 anos)
- Posição (aleatória)
- Clube (aleatório)
A rota deve permitir ainda a inserção da query string filtro=idade, que faz com que a idade seja convertida em um valor textual, seguindo a tabela abaixo:
| Nivel | Texto |
| 17 a 21 | novato |
| 22 a 28 | profissional |
| 29 a 34 | veterano |
| 35+ | master |
Para a geração, utilize o arquivo gerador_jogador.json.
Exercícios Complementares
Utilizando a rota da API abaixo, implemente uma página estática contendo um formulário que permita ao usuário realizar uma pesquisa, e em seguida seja redirecionado para uma página que contenha um JSON com os seguintes valores:
namebirth_yeargenderhomeworld.namehomeworld.climatehomeworld.population
//Requisição via GET query strings -- Retorna um JSON request.get("https://swapi.dev/api/people/?search=luke", options, callback)Substitua o valor luke pela string repassada pelo formulário. O cliente não deve conhecer os endpoints da API swapi.
Esta query retorna apenas o endpoint para acessar as informações de homeworld, sendo necessário executar uma nova requisição para acessar as informações adicionais.