Skip to content

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ão POST, PUT e DELETE 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);
Pontos chave do 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:

  1. Adicionar um botão "Editar" ao lado do botão "Excluir" para cada nave.
  2. Ao clicar em "Editar", preencher o formulário (pode-se usar o mesmo de criação) com os dados atuais da nave.
  3. Mudar o texto do botão "Lançar" para "Atualizar".
  4. Ao enviar o formulário, enviar uma requisição PUT para /spaceships/{id} com o corpo completo do objeto.
  5. Após a atualização bem-sucedida, atualizar a lista da frota.

Dica: Você precisará de fetch com method: 'PUT', cabeçalhos Content-Type e body com JSON.stringify(), exatamente como na requisição POST.


Quiz para fixação

1. Qual parâmetro `fetch` é usado para enviar dados no corpo da requisição?

2. O cabeçalho `'Content-Type': 'application/json'` informa ao servidor que...

3. A função `JSON.stringify(obj)` em JavaScript faz o quê?

4. Para enviar uma requisição `DELETE` usando `fetch`, é obrigatório especificar:

5. Delegação de eventos em JavaScript é quando...


🚀 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 do data-ship-id.