Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Buscando Dados da API

Os cards até agora têm dados escritos diretamente no HTML. Isso não escala: toda vez que alguém cria um evento no TamoJunto, alguém teria que editar o arquivo HTML. O que precisamos é buscar os dados da API construída no capítulo anterior.

Servindo a página pelo backend

Antes de fazer o fetch, tem um detalhe de infraestrutura. Se você abrir o arquivo HTML com duplo clique, o navegador carrega ele via protocolo file://. Nesse caso, uma chamada fetch("http://localhost:3000/api/events") vai ser bloqueada pelo navegador — uma política de segurança chamada CORS (Cross-Origin Resource Sharing) impede que uma página de uma origem (file://) faça requisições para outra (http://localhost:3000)1.

A solução mais simples: servir a página HTML pelo próprio backend. Assim, a página e a API estão na mesma origem, e o navegador permite a requisição sem restrições.

Crie um diretório web/ na raiz do projeto e mova o index.html para lá. Depois, adicione uma linha no app.ts do backend, antes das rotas da API:

import path from "path";

// ... (antes das rotas)
app.use(express.static(path.join(__dirname, "../../web")));
app.use(eventsRoutes);

Código 6-6: Servindo arquivos estáticos do diretório web/ pelo Express.

Agora acesse http://localhost:3000/ no navegador — a página carrega. E como a página está na mesma origem que a API, o fetch vai funcionar sem problemas.

Renderizando a lista com fetch

Remova os cards estáticos do HTML. Deixe apenas o contêiner vazio:

Arquivo: web/index.html
<body>
  <h1>TamoJunto — Eventos</h1>
  <div id="event-list"></div>

  <script>
    async function loadEvents() {
      const response = await fetch("/api/events");
      const events = await response.json();

      const container = document.getElementById("event-list");

      for (const ev of events) {
        const card = document.createElement("article");

        const title = document.createElement("h2");
        title.textContent = ev.title;

        const date = document.createElement("time");
        date.setAttribute("datetime", ev.date);
        date.textContent = new Date(ev.date).toLocaleString("pt-BR", {
          dateStyle: "short",
          timeStyle: "short",
        });

        const desc = document.createElement("p");
        desc.textContent = ev.description;

        const location = document.createElement("p");
        location.textContent = `📍 ${ev.location}`;

        const info = document.createElement("p");
        info.textContent =
          `Vagas: ${ev.capacity} · Organizado por ${ev.organizer_name}`;

        const btn = document.createElement("button");
        btn.textContent = "RSVP";

        card.append(title, date, desc, location, info, btn);
        container.appendChild(card);
      }
    }

    loadEvents();
  </script>
</body>

Código 6-7: Renderizando os 12 eventos a partir da API com manipulação direta do DOM.

Recarregue a página. Os 12 eventos aparecem, com dados reais vindos do banco de dados. Abra o DevTools do navegador (F12), vá na aba “Network” e recarregue: você verá a requisição GET /api/events e a resposta JSON com os 12 objetos.

O que esse código faz, passo a passo:

  1. fetch("/api/events") dispara uma requisição HTTP GET para a API. O await espera a resposta chegar.
  2. response.json() lê o corpo da resposta e parseia o JSON, retornando um array de objetos JavaScript.
  3. Para cada evento, criamos elementos HTML com document.createElement, preenchemos seus conteúdos com textContent e os montamos dentro do card com append.
  4. Cada card é adicionado ao contêiner com appendChild.

A data chega como string ISO ("2026-09-15T11:00:00.000Z") e precisa ser formatada para o leitor. new Date(ev.date).toLocaleString("pt-BR") converte para o formato brasileiro:

15/09/2026, 08:00

O que falta

Esse código não trata erros. Se o backend estiver fora do ar, a página fica em branco — nenhuma mensagem, nenhuma indicação de que algo deu errado. Também não mostra nenhum feedback enquanto os dados carregam. Esses problemas existem, mas vamos tolerá-los por agora. O próximo capítulo introduz um framework que torna esses cenários muito mais simples de lidar.


  1. CORS é o mecanismo pelo qual o navegador decide se uma página pode fazer requisições para um servidor de outra origem. Veremos CORS em detalhes quando implementarmos autenticação, onde as requisições do frontend precisam enviar cookies para o backend. ↩