Capítulo 17
Front e API juntos no local
2 min de leitura 425 palavras 1 gravura
Neste capítulo você vai servir a página do Ateliê e a API na mesma origem. O projeto-fio é o Ateliê Boa Viagem, ateliê digital fictício em Boa Viagem, Recife.
Seu ponto de partida
Use o exemplo 17-fullstack-local do pacote anexo e copie inicio/ para uma pasta de prática fora do original. A raiz do exemplo é a referência completa desta etapa.
Use servidor só em 127.0.0.1 quando o README do exemplo pedir HTTP local. Abrir ou testar não publica nada.
Como praticar
Leia → copie ou digite → mude uma coisa → preveja → salve → recarregue → confira. Restaure cada experiência antes da próxima. Faça as atividades antes de abrir as respostas comentadas.
Arquivos estáticos + API
O servidor entrega index.html em / e JSON em /api/oficinas. O front usa fetch relativo.
Faça na sua cópia
Confira o trecho no contexto do exemplo antes de mudar.
fetch('/api/oficinas').then(r => r.json()).then(render)
Mude uma coisa e preveja
Mostre os nomes numa lista.
Anote o que espera observar antes de salvar e recarregar.
Recarregue e confira
A lista reflete o arquivo.
Se não acontecer
Suba o servidor Node do exemplo, não só http.server do Python.

Formulário chama POST
O submit envia JSON. Após 201, recarregue a lista.
Faça na sua cópia
Confira o trecho no contexto do exemplo antes de mudar.
await fetch('/api/oficinas', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ nome })
});
Mude uma coisa e preveja
Limpe o campo após sucesso.
Anote o que espera observar antes de salvar e recarregar.
Recarregue e confira
Lista atualiza sem recarregar a página inteira.
Se não acontecer
Trate !response.ok.
Espírito local first
Não exigimos nuvem paga. Testes e demo rodam na sua máquina. Serviços externos ficam como próximo passo opcional, fora deste capítulo.
Faça na sua cópia
Confira o trecho no contexto do exemplo antes de mudar.
127.0.0.1 → estudo
produção → outra decisão
Mude uma coisa e preveja
Anote a porta usada no README do exemplo.
Anote o que espera observar antes de salvar e recarregar.
Recarregue e confira
Você sabe encerrar o processo.
Se não acontecer
Ctrl+C no terminal do Node.
Atividades
Atividade 1
Por que fetch(‘/api/oficinas’) sem host?
Atividade 2
O que fazer após POST 201?
Atividade 3
Este volume exige conta em nuvem?
Respostas comentadas
Resposta da atividade 1
Mesma origem do documento servido.
Resposta da atividade 2
Atualizar a lista na interface.
Resposta da atividade 3
Não.
O arquivo completo
Referência do exemplo 17-fullstack-local, reproduzida aqui para que você possa conferir sem sair da página.
public/index.html
<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Ateliê + API</title>
<link rel="stylesheet" href="/styles.css">
</head>
<body>
<a class="skip" href="#conteudo">Ir para o conteúdo</a>
<header><p><strong>Ateliê Boa Viagem</strong></p></header>
<main id="conteudo">
<h1>Front e API</h1>
<ul id="lista"></ul>
<form id="form">
<label for="nome">Nova oficina</label>
<input id="nome" required>
<button type="submit">Enviar</button>
</form>
<p id="msg" role="status"></p>
</main>
<script src="/app.js"></script>
</body>
</html>
public/app.js
async function carregar() {
const r = await fetch('/api/oficinas');
const dados = await r.json();
const ul = document.getElementById('lista');
ul.innerHTML = '';
dados.forEach((o) => {
const li = document.createElement('li');
li.textContent = o.nome;
ul.appendChild(li);
});
}
document.getElementById('form').addEventListener('submit', async (e) => {
e.preventDefault();
const nome = document.getElementById('nome').value.trim();
const r = await fetch('/api/oficinas', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ nome }),
});
const msg = document.getElementById('msg');
if (!r.ok) { msg.textContent = 'Falha ao salvar'; return; }
document.getElementById('nome').value = '';
msg.textContent = 'Salvo';
carregar();
});
carregar();