Criando uma API - Node.js
Usando Express e Node.js, podemos implementar uma API completa no conceito REST para interagir com o usuário. A arquitetura REST propõe a aplicação dos seguintes métodos ou tipos de requisições HTTP para interagir com o servidor:
: obter informações do servidorGET
: enviar informações para o servidorPOST
: atualizar informações no servidorPUT
: remover informações do servidorDELETE
O REST é especialmente conveniente ao criar qualquer tipo de Single Page Application. Vamos ver como criar nossa própria API. Para um novo projeto, vamos criar uma nova pasta. Em seguida, adicionaremos o pacote express ao projeto usando o comando:
npm install express
Neste caso, vamos criar um projeto experimental, que demonstrará a aplicação de REST em uma aplicação usando Node.js e Express. Para processar as requisições, vamos definir o seguinte arquivo app.js
const express = require("express");
const app = express();
app.use(express.json());
app.use(express.static("public"));
// Base de dados condicional
const users = [];
let id = 1; // para definir identificadores
// Função auxiliar para encontrar o índice do usuário pelo id
function findUserIndexById(id) {
for(let i = 0; i < users.length; i++) {
if(users[i].id == id) return i;
}
return -1;
}
app.get("/api/users", function(_, res) {
res.send(users);
});
// Obtenção de um usuário pelo id
app.get("/api/users/:id", function(req, res) {
const id = req.params.id; // Obtendo o id
// Encontrando o usuário no array pelo id
const index = findUserIndexById(id);
// Enviando o usuário
if(index > -1){
res.send(users[index]);
} else {
res.status(404).send("User not found");
}
});
// Recebendo dados enviados
app.post("/api/users", function (req, res) {
if(!req.body) return res.sendStatus(400);
const userName = req.body.name;
const userAge = req.body.age;
const user = { name: userName, age: userAge };
// Atribuindo o identificador da variável id e incrementando
user.id = id++;
// Adicionando o usuário ao array
users.push(user);
res.send(user);
});
// Removendo usuário pelo id
app.delete("/api/users/:id", function(req, res) {
const id = req.params.id;
const index = findUserIndexById(id);
if(index > -1) {
// Removendo o usuário do array pelo índice
const user = users.splice(index, 1)[0];
res.send(user);
} else {
res.status(404).send("User not found");
}
});
// Alterando usuário
app.put("/api/users", function(req, res) {
if(!req.body) return res.sendStatus(400);
const id = req.body.id;
const userName = req.body.name;
const userAge = req.body.age;
const index = findUserIndexById(id);
if(index > -1) {
// Alterando os dados do usuário
const user = users[index];
user.age = userAge;
user.name = userName;
res.send(user);
} else {
res.status(404).send("User not found");
}
});
app.listen(3000, () => console.log("Servidor iniciado em http://localhost:3000"));
Nesta aplicação, para simplificar, utilizaremos um array simples users
const users = [];
Cada objeto que será adicionado a este array terá um identificador numérico específico. Para definir os identificadores dos objetos ao criá-los, definimos a variável id
let id = 1;
Também precisaremos de uma função auxiliar para encontrar o índice de um usuário pelo id
function findUserIndexById(id) {
for (let i = 0; i < users.length; i++) {
if (users[i].id == id) return i;
}
return -1;
}
Se o usuário for encontrado, será retornado o índice dele. Se não for encontrado, será retornado o número -1.
Para processar as requisições, foram definidos cinco métodos para cada tipo de requisição: app.get()
app.post()
app.delete()
app.put()
Quando a aplicação recebe uma requisição do tipo GET no endereço api/users
app.get("/api/users", function(req, res) {
res.send(users);
});
Como resultado do processamento, devemos enviar o array de usuários usando o método res.send()
De maneira semelhante, funciona outro método app.get()
id
app.get("/api/users/:id", function(req, res) {
const id = req.params.id; // Obtendo o id
// Encontrando o usuário no array pelo id
const index = findUserIndexById(id);
// Enviando o usuário
if (index > -1) {
res.send(users[index]);
} else {
res.status(404).send("User not found");
}
});
A única diferença neste caso é que precisamos encontrar o usuário desejado pelo id
res.status(404).send()
Ao receber uma requisição do tipo POST, extraímos os dados enviados pelo cliente da seguinte maneira:
app.post("/api/users", function(req, res) {
if (!req.body) return res.sendStatus(400);
const userName = req.body.name;
const userAge = req.body.age;
const user = { name: userName, age: userAge };
// Atribuindo o identificador da variável id e incrementando
user.id = id++;
// Adicionando o usuário ao array
users.push(user);
res.send(user);
});
Como no início do arquivo configuramos o parsing automático para JSON na pipeline de processamento das requisições, o corpo da requisição será um objeto JSON, do qual podemos extrair as propriedades name
age
id
Ao remover um usuário, realizamos ações semelhantes, mas agora extraímos do array o objeto que será removido:
// Removendo usuário pelo id
app.delete("/api/users/:id", function(req, res) {
const id = req.params.id;
const index = findUserIndexById(id);
if (index > -1) {
// Removendo o usuário do array pelo índice
const user = users.splice(index, 1)[0];
res.send(user);
} else {
res.status(404).send("User not found");
}
});
Se o usuário não for encontrado, retornamos o código de status 404.
Se precisarmos alterar um usuário, usamos o método app.put
app.put("/api/users", function(req, res) {
if (!req.body) return res.sendStatus(400);
const id = req.body.id;
const userName = req.body.name;
const userAge = req.body.age;
const index = findUserIndexById(id);
if (index > -1) {
// Alterando os dados do usuário
const user = users[index];
user.age = userAge;
user.name = userName;
res.send(user);
} else {
res.status(404).send("User not found");
}
});
Para buscar o objeto a ser alterado, encontramos seu índice pelo id
Assim, definimos a API mais simples possível. Agora, vamos adicionar o código do cliente. Conforme estabelecido no código, o Express utiliza a pasta public
index.html
meu-projeto │ ├── app.js │ ├── package.json │ ├── node_modules │ └── public └── index.html
Em seguida, definiremos o seguinte código no arquivo index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>Programício</title>
<style>
td, th {padding: 5px; min-width: 90px; max-width: 200px; text-align: start;}
.btn {padding: 4px; border: 1px solid #333; background-color: #eee; border-radius: 2px; margin: 5px; cursor: pointer;}
</style>
</head>
<body>
<h2>Lista de Usuários</h2>
<form name="userForm">
<input type="hidden" name="id" value="0" />
<p>
<label>Nome:</label><br>
<input name="name" />
</p>
<p>
<label>Idade:</label><br>
<input name="age" type="number" />
</p>
<p>
<button id="submitBtn" type="submit">Salvar</button>
<button id="resetBtn">Resetar</button>
</p>
</form>
<table>
<thead><tr><th>Id</th><th>Nome</th><th>Idade</th><th></th></tr></thead>
<tbody></tbody>
</table>
<script>
const tbody = document.querySelector("tbody");
// Obtenção de todos os usuários
async function getUsers() {
const response = await fetch("/api/users", {
method: "GET",
headers: { "Accept": "application/json" }
});
if (response.ok === true) {
const users = await response.json();
users.forEach(user => {
tbody.append(row(user));
});
}
}
// Obtenção de um usuário
async function getUser(id) {
const response = await fetch("/api/users/" + id, {
method: "GET",
headers: { "Accept": "application/json" }
});
if (response.ok === true) {
const user = await response.json();
const form = document.forms["userForm"];
form.elements["id"].value = user.id;
form.elements["name"].value = user.name;
form.elements["age"].value = user.age;
}
}
// Adição de usuário
async function createUser(userName, userAge) {
const response = await fetch("api/users", {
method: "POST",
headers: { "Accept": "application/json", "Content-Type": "application/json" },
body: JSON.stringify({ name: userName, age: parseInt(userAge, 10) })
});
if (response.ok === true) {
const user = await response.json();
reset();
tbody.append(row(user));
}
}
// Edição de usuário
async function editUser(userId, userName, userAge) {
const response = await fetch("api/users", {
method: "PUT",
headers: { "Accept": "application/json", "Content-Type": "application/json" },
body: JSON.stringify({ id: userId, name: userName, age: parseInt(userAge, 10) })
});
if (response.ok === true) {
const user = await response.json();
reset();
document.querySelector(`tr[data-rowid="${user.id}"]`).replaceWith(row(user));
}
}
// Remoção de usuário
async function deleteUser(id) {
const response = await fetch("/api/users/" + id, {
method: "DELETE",
headers: { "Accept": "application/json" }
});
if (response.ok === true) {
const user = await response.json();
document.querySelector(`tr[data-rowid="${user.id}"]`).remove();
}
}
// Resetar formulário
function reset() {
const form = document.forms["userForm"];
form.reset();
form.elements["id"].value = 0;
}
// Criação de linha para a tabela
function row(user) {
const tr = document.createElement("tr");
tr.setAttribute("data-rowid", user.id);
const idTd = document.createElement("td");
idTd.append(user.id);
tr.append(idTd);
const nameTd = document.createElement("td");
nameTd.append(user.name);
tr.append(nameTd);
const ageTd = document.createElement("td");
ageTd.append(user.age);
tr.append(ageTd);
const linksTd = document.createElement("td");
const editLink = document.createElement("a");
editLink.setAttribute("data-id", user.id);
editLink.setAttribute("class", "btn");
editLink.append("Editar");
editLink.addEventListener("click", e => {
e.preventDefault();
getUser(user.id);
});
linksTd.append(editLink);
const removeLink = document.createElement("a");
removeLink.setAttribute("data-id", user.id);
removeLink.setAttribute("class", "btn");
removeLink.append("Deletar");
removeLink.addEventListener("click", e => {
e.preventDefault();
deleteUser(user.id);
});
linksTd.append(removeLink);
tr.appendChild(linksTd);
return tr;
}
// Resetar valores do formulário
document.getElementById("resetBtn").addEventListener("click", e => {
e.preventDefault();
reset();
});
// Envio do formulário
document.forms["userForm"].addEventListener("submit", e => {
e.preventDefault();
const form = document.forms["userForm"];
const id = form.elements["id"].value;
const name = form.elements["name"].value;
const age = form.elements["age"].value;
if (id == 0)
createUser(name, age);
else
editUser(id, name, age);
});
// Carregar usuários
getUsers();
</script>
</body>
</html>
A lógica principal está contida no código JavaScript. Ao carregar a página no navegador, todos os objetos são obtidos do banco de dados pela função getUsers
async function getUsers() {
// Envia a requisição e obtém a resposta
const response = await fetch("/api/users", {
method: "GET",
headers: { "Accept": "application/json" {
{);
// Se a requisição for bem-sucedida
if (response.ok === true) {
// Obtém os dados
const users = await response.json();
users.forEach(user => {
// Adiciona os elementos recebidos na tabela
tbody.append(row(user));
{);
{
{
Para adicionar linhas na tabela, utilizamos a função row()
Para obter um usuário específico, usamos a função getUser()
async function getUser(id) {
const response = await fetch("/api/users/" + id, {
method: "GET",
headers: { "Accept": "application/json" }
});
if (response.ok === true) {
const user = await response.json();
const form = document.forms["userForm"];
form.elements["id"].value = user.id;
form.elements["name"].value = user.name;
form.elements["age"].value = user.age;
}
}
O usuário específico é adicionado ao formulário acima da tabela. Este mesmo formulário é utilizado tanto para adicionar quanto para editar um objeto. Com um campo oculto que armazena o id do usuário, podemos determinar qual ação está sendo executada: adicionar ou editar. Se o id for igual a 0, a função createUser
async function createUser(userName, userAge) {
const response = await fetch("api/users", {
method: "POST",
headers: { "Accept": "application/json", "Content-Type": "application/json" },
body: JSON.stringify({
name: userName,
age: parseInt(userAge, 10)
})
});
if (response.ok === true) {
const user = await response.json();
reset();
tbody.append(row(user));
}
}
Se o usuário já foi carregado no formulário e seu id
Ao executar a aplicação e acessar no navegador o endereço http://localhost:3000

