Mudanças entre as edições de "Javascript: CRUD Rest"
De Aulas
(Criou página com 'Afluentes: Desenvolvimento Front-end I, Desenvolvimento Front-end II, Usabilidade, desenvolvimento web, mobile e jogos') |
(→api.js) |
||
(6 revisões intermediárias pelo mesmo usuário não estão sendo mostradas) | |||
Linha 1: | Linha 1: | ||
− | Afluentes: [[Desenvolvimento Front-end I]], [[ | + | |
+ | |||
+ | |||
+ | |||
+ | Afluentes: [[Desenvolvimento Front-end I]], [[Usabilidade, desenvolvimento web, mobile e jogos]]. | ||
+ | |||
+ | = Serviço web = | ||
+ | |||
+ | Para que nosso CRUD possa ser funcional, precisamos de um serviço web com as operações de CRUD (CREATE, READ, UPDATE e DELETE). Para o nosso exemplo aqui, usarei um serviço web desenvolvido em linguagem de programação GO: | ||
+ | |||
+ | * [[Go: RESTful - exemplo com persistência, gorm, e segurança]] | ||
+ | |||
+ | Caso você queira reimplementar o serviço em Node.js ou outra linguagem/framework, basta entender o manual de acesso ao serviço web: | ||
+ | * [[Go: RESTful - um exemplo completo com persistência#Manual de Utilização]] | ||
+ | |||
+ | = index.html = | ||
+ | |||
+ | O arquivo <code>index.html</code> contem a formatação básica da nossa aplicação | ||
+ | |||
+ | <syntaxhighlight lang="html"> | ||
+ | <!doctype html> | ||
+ | <html lang="pt-br"> | ||
+ | |||
+ | <head> | ||
+ | <meta charset="utf-8"> | ||
+ | <title>Usuários</title> | ||
+ | <script src="script.js"></script> | ||
+ | <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css" /> | ||
+ | <link rel="stylesheet" href="style.css"> | ||
+ | </head> | ||
+ | |||
+ | <body onload="carregarDados();"> | ||
+ | <h1>Usuários</h1> | ||
+ | <p> | ||
+ | <label for="id">ID:</label> | ||
+ | <input type="text" id="id"> | ||
+ | </p> | ||
+ | <p> | ||
+ | <label for="name">Nome:</label> | ||
+ | <input type="text" id="name"> | ||
+ | </p> | ||
+ | <p> | ||
+ | <label for="email">E-mail:</label> | ||
+ | <input type="text" id="email"> | ||
+ | </p> | ||
+ | <p class="btn-group"> | ||
+ | <button class="button" onclick="gravar();">Gravar</button> | ||
+ | <button class="button" onclick="limpar();">Limpar</button> | ||
+ | <button class="button" onclick="carregarDados();limpar();">Recarregar</button> | ||
+ | </p> | ||
+ | <table> | ||
+ | <thead> | ||
+ | <tr> | ||
+ | <th>ID</th> | ||
+ | <th>Nome</th> | ||
+ | <th>E-mail</th> | ||
+ | <th>Ações</th> | ||
+ | </tr> | ||
+ | </thead> | ||
+ | <tbody id="tbody"> | ||
+ | </tbody> | ||
+ | </table> | ||
+ | </body> | ||
+ | |||
+ | </html> | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | = api.js = | ||
+ | |||
+ | O arquivo <code>api.js</code> contem os códigos em javascript para o acesso às operações GET, POST, PUT e DELETE do nosso serviço web. | ||
+ | |||
+ | <syntaxhighlight lang="javascript"> | ||
+ | /** | ||
+ | * Vamos precisar de um link para acessar nosso serviço. No caso, estamos | ||
+ | * utilizando o localhost na porta 8080 e nosso endpoint é /users | ||
+ | * Veja que nesse exemplo estamos acessando um serviço que requer autenticação | ||
+ | * usando X-KEY e X-API-KEY, então já configuramos o cabeçalho com esses | ||
+ | * parâmetros. | ||
+ | */ | ||
+ | |||
+ | //var url = "http://localhost:8080/users"; | ||
+ | var url = 'https://api.arisa.com.br/users'; | ||
+ | const headers = { | ||
+ | 'Content-Type': 'application/json; charset=utf-8', // Mensagens JSON | ||
+ | "X-User": "fulano", // Usuário | ||
+ | 'X-API-KEY': "12345", // API-KEY | ||
+ | }; | ||
+ | |||
+ | /** | ||
+ | * Função assíncrona para carregar os dados na tabela | ||
+ | */ | ||
+ | async function carregarDados() { | ||
+ | let tbody = document.getElementById('tbody'); // instanciamos o corpo da tabela | ||
+ | tbody.innerHTML = ""; // e limpamos seu conteúdo | ||
+ | try { | ||
+ | const response = await fetch(url, { // Fazemos a chamada ao serviço | ||
+ | method: 'GET', // usando a operação GET | ||
+ | headers: headers, // e passamos os cabeçalhos | ||
+ | }); | ||
+ | const result = await response.json(); // retorna uma lista de objetos JSON | ||
+ | result.forEach(row => { // para cada objeto da lista | ||
+ | let tr = document.createElement("tr"); // cria uma linha da tabela | ||
+ | tr.innerHTML = (` | ||
+ | <td>${row.id}</td> | ||
+ | <td onClick="selecionar(${row.id});">${row.name}</td> | ||
+ | <td>${row.email}</td> | ||
+ | <td> | ||
+ | <button | ||
+ | type="button" | ||
+ | onClick="excluir(${row.id});" | ||
+ | >Excluir</button> | ||
+ | </td> | ||
+ | `); | ||
+ | tbody.appendChild(tr); // Criada a linha, adicionamos | ||
+ | }); // no corpo da tabela | ||
+ | } catch (error) { | ||
+ | alert("Error: " + error); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * Retorna apenas um objeto JSON com o id selected_id | ||
+ | */ | ||
+ | async function selecionar(selected_id) { | ||
+ | let id = document.getElementById('id'); | ||
+ | id.disabled = true; // Desabilitamos o campo ID porque | ||
+ | let name = document.getElementById('name'); // vamos alterar pelo ID | ||
+ | let email = document.getElementById('email'); | ||
+ | try { | ||
+ | // Buscamos pela url com parâmetro id | ||
+ | const response = await fetch(`${url}/${selected_id}`, { | ||
+ | method: "GET", | ||
+ | headers: headers, | ||
+ | }); | ||
+ | const user = await response.json(); // Retorna um objeto e carregamos as | ||
+ | id.value = user.id; // informações retornadas nos campos texto | ||
+ | name.value = user.name; | ||
+ | email.value = user.email; | ||
+ | } catch (error) { | ||
+ | alert("Error: " + error); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | async function excluir(id) { | ||
+ | try { | ||
+ | // Usamos o serviço chamando pelo ID | ||
+ | const response = await fetch(`${url}/${id}`, { // Excluimos pelo ID | ||
+ | method: "DELETE", // chamamos a operação DELETE | ||
+ | headers: headers, | ||
+ | }); | ||
+ | const result = await response.json(); | ||
+ | limpar(); | ||
+ | carregarDados(); | ||
+ | } catch (error) { | ||
+ | alert("Error: " + error); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * Gravamos um objeto com os dados carregados dos campos texto | ||
+ | */ | ||
+ | async function gravar() { | ||
+ | let id = document.getElementById('id'); | ||
+ | let name = document.getElementById('name'); | ||
+ | let email = document.getElementById('email'); | ||
+ | let i_id = 0; | ||
+ | if (isNaN(i_id = parseInt(id.value))) { // O id precisa ser um número inteiro | ||
+ | alert("O id precisa ser um inteiro."); | ||
+ | return; | ||
+ | } | ||
+ | var data = JSON.stringify({ // Criamos nosso objeto JSON Para o envio | ||
+ | id: i_id, | ||
+ | name: name.value, | ||
+ | email: email.value, | ||
+ | }); | ||
+ | // Se o campo ID estiver desabilitado, é porque estávamos alterando, | ||
+ | // então usa PUT, senão POST, pois é um novo registro. | ||
+ | let method = id.disabled ? 'PUT' : 'POST'; | ||
+ | try { | ||
+ | const response = await fetch(url, { | ||
+ | method: method, | ||
+ | headers: headers, | ||
+ | body: data, | ||
+ | }).then(result => { // Se deu tudo ok | ||
+ | limpar(); // limpa os campos e habilita o id | ||
+ | carregarDados(); // e recarrega os dados da tabela | ||
+ | }); | ||
+ | } catch (error) { | ||
+ | alert("Error: " + error); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * Limpa os campos e habilita o campo ID que poderia | ||
+ | * estar desabilitado. | ||
+ | */ | ||
+ | function limpar() { | ||
+ | let id = document.getElementById('id'); | ||
+ | id.value = ""; | ||
+ | id.disabled = false; | ||
+ | document.getElementById('name').value = ""; | ||
+ | document.getElementById('email').value = ""; | ||
+ | |||
+ | } | ||
+ | |||
+ | </syntaxhighlight> | ||
+ | |||
+ | = index.css = | ||
+ | |||
+ | Estou usando um CSS para deixar a parte visual mais bonita, mas o uso é opcional. | ||
+ | |||
+ | <syntaxhighlight lang=css> | ||
+ | table { | ||
+ | width: 100%; | ||
+ | } | ||
+ | |||
+ | th { | ||
+ | background-color: #04AA6D; | ||
+ | color: white; | ||
+ | } | ||
+ | |||
+ | td { | ||
+ | text-align: left; | ||
+ | padding: 8px; | ||
+ | } | ||
+ | |||
+ | tr:nth-child(even) { | ||
+ | background-color: #f2f2f2; | ||
+ | } | ||
+ | |||
+ | input[type=number], | ||
+ | input[type=text], | ||
+ | select { | ||
+ | width: 100%; | ||
+ | padding: 12px 20px; | ||
+ | margin: 8px 0; | ||
+ | display: inline-block; | ||
+ | border: 1px solid #ccc; | ||
+ | border-radius: 4px; | ||
+ | box-sizing: border-box; | ||
+ | } | ||
+ | |||
+ | input[type=submit] { | ||
+ | width: 100%; | ||
+ | background-color: #4CAF50; | ||
+ | color: white; | ||
+ | padding: 14px 20px; | ||
+ | margin: 8px 0; | ||
+ | border: none; | ||
+ | border-radius: 4px; | ||
+ | cursor: pointer; | ||
+ | } | ||
+ | |||
+ | input[type=submit]:hover { | ||
+ | background-color: #45a049; | ||
+ | } | ||
+ | |||
+ | div { | ||
+ | border-radius: 5px; | ||
+ | background-color: #f2f2f2; | ||
+ | padding: 20px; | ||
+ | } | ||
+ | |||
+ | input[type=submit], | ||
+ | input[type=reset] { | ||
+ | background-color: #04AA6D; | ||
+ | border: none; | ||
+ | color: white; | ||
+ | padding: 16px 32px; | ||
+ | text-decoration: none; | ||
+ | margin: 4px 2px; | ||
+ | cursor: pointer; | ||
+ | } | ||
+ | |||
+ | .btn-group .button { | ||
+ | background-color: #04AA6D; | ||
+ | /* Green */ | ||
+ | border: none; | ||
+ | color: white; | ||
+ | padding: 10px 16px; | ||
+ | text-align: center; | ||
+ | text-decoration: none; | ||
+ | display: inline-block; | ||
+ | font-size: 16px; | ||
+ | cursor: pointer; | ||
+ | } | ||
+ | |||
+ | .btn-group .button:hover { | ||
+ | background-color: #3e8e41; | ||
+ | } | ||
+ | </syntaxhighlight> |
Edição atual tal como às 20h37min de 4 de novembro de 2024
Afluentes: Desenvolvimento Front-end I, Usabilidade, desenvolvimento web, mobile e jogos.
Serviço web
Para que nosso CRUD possa ser funcional, precisamos de um serviço web com as operações de CRUD (CREATE, READ, UPDATE e DELETE). Para o nosso exemplo aqui, usarei um serviço web desenvolvido em linguagem de programação GO:
Caso você queira reimplementar o serviço em Node.js ou outra linguagem/framework, basta entender o manual de acesso ao serviço web:
index.html
O arquivo index.html
contem a formatação básica da nossa aplicação
<!doctype html>
<html lang="pt-br">
<head>
<meta charset="utf-8">
<title>Usuários</title>
<script src="script.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css" />
<link rel="stylesheet" href="style.css">
</head>
<body onload="carregarDados();">
<h1>Usuários</h1>
<p>
<label for="id">ID:</label>
<input type="text" id="id">
</p>
<p>
<label for="name">Nome:</label>
<input type="text" id="name">
</p>
<p>
<label for="email">E-mail:</label>
<input type="text" id="email">
</p>
<p class="btn-group">
<button class="button" onclick="gravar();">Gravar</button>
<button class="button" onclick="limpar();">Limpar</button>
<button class="button" onclick="carregarDados();limpar();">Recarregar</button>
</p>
<table>
<thead>
<tr>
<th>ID</th>
<th>Nome</th>
<th>E-mail</th>
<th>Ações</th>
</tr>
</thead>
<tbody id="tbody">
</tbody>
</table>
</body>
</html>
api.js
O arquivo api.js
contem os códigos em javascript para o acesso às operações GET, POST, PUT e DELETE do nosso serviço web.
/**
* Vamos precisar de um link para acessar nosso serviço. No caso, estamos
* utilizando o localhost na porta 8080 e nosso endpoint é /users
* Veja que nesse exemplo estamos acessando um serviço que requer autenticação
* usando X-KEY e X-API-KEY, então já configuramos o cabeçalho com esses
* parâmetros.
*/
//var url = "http://localhost:8080/users";
var url = 'https://api.arisa.com.br/users';
const headers = {
'Content-Type': 'application/json; charset=utf-8', // Mensagens JSON
"X-User": "fulano", // Usuário
'X-API-KEY': "12345", // API-KEY
};
/**
* Função assíncrona para carregar os dados na tabela
*/
async function carregarDados() {
let tbody = document.getElementById('tbody'); // instanciamos o corpo da tabela
tbody.innerHTML = ""; // e limpamos seu conteúdo
try {
const response = await fetch(url, { // Fazemos a chamada ao serviço
method: 'GET', // usando a operação GET
headers: headers, // e passamos os cabeçalhos
});
const result = await response.json(); // retorna uma lista de objetos JSON
result.forEach(row => { // para cada objeto da lista
let tr = document.createElement("tr"); // cria uma linha da tabela
tr.innerHTML = (`
<td>${row.id}</td>
<td onClick="selecionar(${row.id});">${row.name}</td>
<td>${row.email}</td>
<td>
<button
type="button"
onClick="excluir(${row.id});"
>Excluir</button>
</td>
`);
tbody.appendChild(tr); // Criada a linha, adicionamos
}); // no corpo da tabela
} catch (error) {
alert("Error: " + error);
}
}
/**
* Retorna apenas um objeto JSON com o id selected_id
*/
async function selecionar(selected_id) {
let id = document.getElementById('id');
id.disabled = true; // Desabilitamos o campo ID porque
let name = document.getElementById('name'); // vamos alterar pelo ID
let email = document.getElementById('email');
try {
// Buscamos pela url com parâmetro id
const response = await fetch(`${url}/${selected_id}`, {
method: "GET",
headers: headers,
});
const user = await response.json(); // Retorna um objeto e carregamos as
id.value = user.id; // informações retornadas nos campos texto
name.value = user.name;
email.value = user.email;
} catch (error) {
alert("Error: " + error);
}
}
async function excluir(id) {
try {
// Usamos o serviço chamando pelo ID
const response = await fetch(`${url}/${id}`, { // Excluimos pelo ID
method: "DELETE", // chamamos a operação DELETE
headers: headers,
});
const result = await response.json();
limpar();
carregarDados();
} catch (error) {
alert("Error: " + error);
}
}
/**
* Gravamos um objeto com os dados carregados dos campos texto
*/
async function gravar() {
let id = document.getElementById('id');
let name = document.getElementById('name');
let email = document.getElementById('email');
let i_id = 0;
if (isNaN(i_id = parseInt(id.value))) { // O id precisa ser um número inteiro
alert("O id precisa ser um inteiro.");
return;
}
var data = JSON.stringify({ // Criamos nosso objeto JSON Para o envio
id: i_id,
name: name.value,
email: email.value,
});
// Se o campo ID estiver desabilitado, é porque estávamos alterando,
// então usa PUT, senão POST, pois é um novo registro.
let method = id.disabled ? 'PUT' : 'POST';
try {
const response = await fetch(url, {
method: method,
headers: headers,
body: data,
}).then(result => { // Se deu tudo ok
limpar(); // limpa os campos e habilita o id
carregarDados(); // e recarrega os dados da tabela
});
} catch (error) {
alert("Error: " + error);
}
}
/**
* Limpa os campos e habilita o campo ID que poderia
* estar desabilitado.
*/
function limpar() {
let id = document.getElementById('id');
id.value = "";
id.disabled = false;
document.getElementById('name').value = "";
document.getElementById('email').value = "";
}
index.css
Estou usando um CSS para deixar a parte visual mais bonita, mas o uso é opcional.
table {
width: 100%;
}
th {
background-color: #04AA6D;
color: white;
}
td {
text-align: left;
padding: 8px;
}
tr:nth-child(even) {
background-color: #f2f2f2;
}
input[type=number],
input[type=text],
select {
width: 100%;
padding: 12px 20px;
margin: 8px 0;
display: inline-block;
border: 1px solid #ccc;
border-radius: 4px;
box-sizing: border-box;
}
input[type=submit] {
width: 100%;
background-color: #4CAF50;
color: white;
padding: 14px 20px;
margin: 8px 0;
border: none;
border-radius: 4px;
cursor: pointer;
}
input[type=submit]:hover {
background-color: #45a049;
}
div {
border-radius: 5px;
background-color: #f2f2f2;
padding: 20px;
}
input[type=submit],
input[type=reset] {
background-color: #04AA6D;
border: none;
color: white;
padding: 16px 32px;
text-decoration: none;
margin: 4px 2px;
cursor: pointer;
}
.btn-group .button {
background-color: #04AA6D;
/* Green */
border: none;
color: white;
padding: 10px 16px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 16px;
cursor: pointer;
}
.btn-group .button:hover {
background-color: #3e8e41;
}