Menu
CoddyTech

Uma página que chama a API

Parte da seção APIs REST do Journey de Node.js da Coddy. Lição 21 de 25.

Uma página chama sua API usando fetch. Um POST precisa de três opções: método, cabeçalhos e corpo. Converta o objeto JavaScript em texto JSON para o corpo e indique que esse texto é do tipo application/json.

const response = await fetch('/api/books', {
    method: 'POST',
    headers: {'Content-Type': 'application/json'},
    body: JSON.stringify({title: title}),
});
const data = await response.json();

O primeiro await recebe a resposta HTTP. O segundo lê o corpo JSON dela. response.ok informa se o status está na faixa de sucesso. Um status como 400 ou 409 não rejeita a promessa de fetch; ele retorna uma resposta cujo ok é false. O código do formulário e da lista já foi fornecido; concentre-se em enviar a solicitação e tratar o resultado.

A variável message fornecida se refere ao parágrafo de mensagem da página. Defina o textContent dela como o texto a ser exibido ou como uma string vazia para apagá-lo:

message.textContent = data.error.message;
// Limpe-o após o sucesso:
message.textContent = '';

A página e a API compartilham a mesma origem, então esta chamada não precisa de permissão CORS. FormData codifica um formulário de maneira diferente do JSON; use texto JSON porque esta API usa express.json().

challenge icon

Desafio

Fácil

Sua API ainda não tem uma tela. Crie uma página simples para ela, servida pelo mesmo servidor, cujo formulário adiciona tarefas por meio da API.

  1. Em server.js, sirva a pasta public com express.static, para que GET / retorne public/index.html.
  2. Em public/index.html, o listener de envio já lê o título. Faça com que ele envie a nova tarefa para a API:
    • Use a variável title fornecida, que contém o texto de entrada.
    • Envie-a com fetch('/api/tasks', ...) como um POST.
    • O corpo é um texto JSON criado com JSON.stringify, como {"title":"Water the plants"}.
    • A solicitação precisa do cabeçalho 'Content-Type': 'application/json', na opção headers de fetch; caso contrário, express.json() não lerá o corpo.
  3. Se a resposta estiver OK (a propriedade ok é true para qualquer status de 200 a 299), limpe o formulário com form.reset(), esvazie #message e chame load() para que a lista mostre a nova tarefa.
  4. Caso contrário, o corpo da resposta terá o formato de erro visto anteriormente, por exemplo:
    { "error": { "code": "conflict", "message": "A task with this title already exists" } }
    Mostre a propriedade message no parágrafo #message.

As verificações executam o script desta página fornecido com um pequeno formulário simulado e a API real da lição. Elas enviam uma tarefa e uma duplicata e, em seguida, inspecionam a lista, o formulário e a mensagem. Experimente também a página real ao lado do editor.

Experimente: envie GET /. A página é aberta na visualização da página com as 3 tarefas iniciais. Digite "Water the plants" e pressione Adicionar: o campo de entrada fica vazio e a tarefa aparece no fim da lista. Digite "Water the plants" novamente e pressione Adicionar: a lista permanece igual, e "A task with this title already exists" aparece abaixo do formulário.

Experimente você mesmo

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>Tasks</title>
</head>
<body>
    <h1>Tasks</h1>
    <ul id="list"></ul>
    <form id="add">
        <input name="title" placeholder="New task" required>
        <button>Add</button>
    </form>
    <p id="message"></p>
    <script>
        const list = document.querySelector('#list');
        const form = document.querySelector('#add');
        const message = document.querySelector('#message');

        async function load() {
            const response = await fetch('/api/tasks?limit=50');
            const page = await response.json();
            list.replaceChildren(...page.items.map((task) => {
                const item = document.createElement('li');
                item.textContent = (task.done ? '[x] ' : '[ ] ') + task.title;
                return item;
            }));
        }

        form.addEventListener('submit', async (event) => {
            event.preventDefault();
            const title = form.elements.title.value;
            // Send the title to POST /api/tasks as JSON. On success clear
            // the form and load() again; on an error show its message.
        });

        load();
    </script>
</body>
</html>

Todas as lições de APIs REST

Pratique por conta própria: Playground de Express