Capítulo 4.3: Envio de requisições POST/PUT/DELETE
Tempo de estudo: 1 hora
1. Comandos Ativos: Do Lançamento à Desativação
Até agora, nosso Centro de Controle da Missão apenas solicitava informações (GET
). Agora aprenderemos a enviar comandos ativos:
- POST: "Lançar um novo satélite em órbita!"
- PUT: "Realizar uma modernização completa dos sistemas na ISS!"
- DELETE: "Retirar da órbita a antiga nave
Debris-123
!"
Para isso, usaremos fetch
, mas com parâmetros adicionais que descrevem nosso comando.
💡 Analogia Espacial:
Se
GET
é a escuta passiva da transmissão de rádio, entãoPOST
,PUT
eDELETE
são a transmissão ativa de comandos. Para isso, precisamos não apenas especificar a "frequência" (URL), mas também o conteúdo do comando (corpo da requisição) e o protocolo de comunicação (cabeçalhos).
2. Envio de requisição POST: Lançamento de uma nova nave
Para criar um novo recurso, enviamos uma requisição POST
. O mais importante aqui é passar o corpo (body) da requisição com os dados do novo objeto.
Passo 1: Adicionar o formulário de criação em index.html
Vamos colocá-lo após o bloco "Requisição por ID".
<!-- index.html -->
<hr>
<h2>Lançar nova nave</h2>
<form id="create-ship-form">
<input type="text" id="create-name" placeholder="Nome" required><br>
<input type="text" id="create-type" placeholder="Tipo" required><br>
<input type="number" id="create-year" placeholder="Ano de Lançamento" required><br>
<input type="text" id="create-status" placeholder="Status" required><br>
<button type="submit">Lançar</button>
</form>
<div id="create-status-message"></div>
Passo 2: Adicionar a lógica em app.js
// app.js, no final do arquivo
const createShipForm = document.getElementById('create-ship-form');
const createStatusMessage = document.getElementById('create-status-message');
async function createShip(event) {
event.preventDefault();
// 1. Coletamos os dados do formulário em um objeto
const shipData = {
name: document.getElementById('create-name').value,
type: document.getElementById('create-type').value,
launch_year: parseInt(document.getElementById('create-year').value),
status: document.getElementById('create-status').value
};
try {
createStatusMessage.textContent = 'Enviando comando de lançamento...';
// 2. Enviamos uma requisição fetch com parâmetros
const response = await fetch(`${API_BASE_URL}/spaceships`, {
method: 'POST', // Especifica o método
headers: {
'Content-Type': 'application/json' // Dizemos ao servidor que estamos enviando JSON
},
body: JSON.stringify(shipData) // Transforma o objeto JavaScript em uma string JSON
});
if (!response.ok) {
// Se o servidor retornou um erro, tentamos ler o corpo
const errorData = await response.json();
throw new Error(errorData.detail || `Erro do servidor: ${response.status}`);
}
const newShip = await response.json();
createStatusMessage.textContent = `🚀 Lançamento bem-sucedido! ID atribuído à nave: ${newShip.id}`;
createShipForm.reset(); // Limpa o formulário
fetchAndDisplayFleet(); // Atualiza a lista geral da frota
} catch (error) {
console.error('Erro ao lançar a nave:', error);
createStatusMessage.textContent = `🔴 Erro: ${error.message}`;
}
}
createShipForm.addEventListener('submit', createShip);
fetch
para POST:
method: 'POST'
: Obrigatório especificar o método HTTP.headers: { 'Content-Type': 'application/json' }
: Cabeçalho crucial. Ele informa ao nosso servidor FastAPI que o corpo da requisição contém JSON, e que precisa ser interpretado.body: JSON.stringify(shipData)
: Não podemos enviar um objeto JavaScript diretamente. Ele precisa ser serializado (transformado) em uma string JSON.
3. Envio de requisição DELETE: Desativação de uma nave
A requisição de exclusão é mais simples — geralmente não precisa de corpo, apenas a URL com o ID do objeto.
Passo 1: Adicionar o botão "Excluir" à nossa lista de naves
Modificaremos a função fetchAndDisplayFleet
em app.js
para que ela adicione um botão de exclusão para cada item.
// app.js, dentro da função fetchAndDisplayFleet
// ...
ships.forEach(ship => {
const listItem = document.createElement('li');
// Adiciona um botão com um atributo data que armazena o ID
listItem.innerHTML = `
<strong>${ship.name} (ID: ${ship.id})</strong><br>
Tipo: ${ship.type} | Ano: ${ship.launch_year} | Status: ${ship.status}<br>
<button class="delete-btn" data-ship-id="${ship.id}">Desativar nave</button>
`;
fleetList.appendChild(listItem);
});
// ...
Passo 2: Adicionar um manipulador para todos os botões "Excluir" Usamos delegação de eventos — um único manipulador para toda a lista.
// app.js, no final do arquivo
async function deleteShip(shipId) {
if (!confirm(`Tem certeza de que deseja desativar a nave com ID ${shipId}? Esta ação é irreversível.`)) {
return;
}
try {
const response = await fetch(`${API_BASE_URL}/spaceships/${shipId}`, {
method: 'DELETE' // Especifica o método
});
if (!response.ok) {
throw new Error(`Não foi possível desativar a nave. Status: ${response.status}`);
}
alert(`Nave com ID ${shipId} desativada com sucesso.`);
fetchAndDisplayFleet(); // Atualiza a lista
} catch (error) {
console.error('Erro ao desativar:', error);
alert(`Erro: ${error.message}`);
}
}
// Delegação de eventos: escuta cliques em toda a lista
fleetList.addEventListener('click', (event) => {
// Verifica se o clique foi em um botão com a classe 'delete-btn'
if (event.target.classList.contains('delete-btn')) {
const shipId = event.target.dataset.shipId; // Obtém o ID do atributo data
deleteShip(shipId);
}
});
Passo 3: Adicionar id ao modelo Spaceship
Adiciona id ao modelo e ao banco de dados no arquivo main.py
class Spaceship(BaseModel):
id: int
# Restante do código do modelo...
db_spaceships = {
1: {
"id": 1,
# Dados do elemento 1
},
2: {
"id": 2,
# Dados do elemento 2
},
3: {
"id": 3,
# Dados do elemento 3
}
}
method: 'DELETE'
: Especifica o método. Corpo e cabeçalhos não são necessários aqui.confirm()
: Uma janela de confirmação integrada simples para evitar a exclusão acidental de algo importante.
4. Envio de requisição PUT (Tarefa Autônoma)
A implementação da requisição PUT
para atualização é muito semelhante à POST
.
Sua missão, se decidir aceitá-la:
- Adicionar um botão "Editar" ao lado do botão "Excluir" para cada nave.
- Ao clicar em "Editar", preencher o formulário (pode-se usar o mesmo de criação) com os dados atuais da nave.
- Mudar o texto do botão "Lançar" para "Atualizar".
- Ao enviar o formulário, enviar uma requisição
PUT
para/spaceships/{id}
com o corpo completo do objeto. - Após a atualização bem-sucedida, atualizar a lista da frota.
Dica: Você precisará de
fetch
commethod: 'PUT'
, cabeçalhosContent-Type
ebody
comJSON.stringify()
, exatamente como na requisição POST.
Quiz para fixação
🚀 Resumo do Capítulo:
Seu Centro de Controle da Missão (CCM) agora possui um conjunto completo de comandos para gerenciar a frota!
- ✅ Você aprendeu a enviar
POST
-requisições com corpo e cabeçalhos para criar novos recursos. - ✅ Você implementou
DELETE
-requisições para desativar equipamentos obsoletos. - ✅ Você recebeu a tarefa de implementar uma
PUT
-requisição, consolidando seu conhecimento.
Controle total estabelecido! Mas o que fazer se a conexão for perdida ou o servidor relatar um erro? No próximo capítulo, criaremos um sistema centralizado de tratamento de erros no frontend.
📌 Verificação:
- Certifique-se de que o formulário de criação de nova nave funcione e que a lista na página seja atualizada após a criação bem-sucedida.
- Verifique se o botão "Desativar Equipamento" funciona, solicita confirmação e remove a nave da lista.
- Tente criar uma nave com dados inválidos (por exemplo, com um nome muito curto) e veja o erro que seu servidor FastAPI retornará.
⚠️ Se houver erros:
- Erro
422
do servidor: Provavelmente, os dados que você está enviando não passam pela validação do Pydantic. Verifique o console do navegador —errorData.detail
mostrará em qual campo está o problema.- Erro
415 Unsupported Media Type
: Você se esqueceu de adicionar o cabeçalho'Content-Type': 'application/json'
.- Os botões de exclusão não funcionam: Verifique se a delegação de eventos está funcionando corretamente e se você está obtendo o
shipId
dodata-ship-id
.