Paulo Queiroz

Seu Primeiro Backend 🔥 — Parte 2

Neste post continuaremos o desenvolvimento do nosso backend. Desta vez, lidararemos com o envio de formulários para receber dados do cliente e armazená-los no nosso servidor. Este é o próximo passo na nossa jornada para criar uma API REST.

Lidando com Envio de Formulários

Vá até o index.html e adicione um formulário ao body. Este formulário será usado para enviar dados ao nosso servidor.

<form id="form" action="http://localhost:3000/add-student" method="post">
  <input type="text" name="name" placeholder="Nome" required />
  <input type="number" name="age" placeholder="Idade" required />
  <button type="submit">Enviar</button>
</form>

Esse formulário possui um campo de entrada para o nome do estudante, um para a idade do estudante e um botão de envio. O atributo action especifica a URL para onde os dados do formulário serão submetidos. Já o atributo method especifica o método HTTP a ser usado. Nessse caso, estamos usando o método POST.

Curiosamente, os formulários HTML não tem suporte à todos os métodos HTTP. Os únicos métodos suportados são GET e POST. Precisaremos do auxílio do JavaScript para usar os outros métodos, mas isso não será necessario agora, visto que estamos interessados somente no POST.

Agora, vamos adicionar um end-point ao nosso servidor para lidar com o envio do formulário. Adicione o seguinte código ao index.js.

app.post("/add-student", (req, res) => {
  const { name, age } = req.body;
  students.push({ name, age: parseInt(age) });
  res.send("Aluno adicionado com sucesso");
});

Isso não vai funcionar ainda. Nós precisamos dizer ao Express para interpretar os dados do pedido. Adicione a seguinte linha após app.use(cors());.

app.use(express.urlencoded({ extended: true }));

Agora estamos prontos! Abra o index.html no navegador, preencha e envie o formulário.

Envio do formulário

Se tudo tiver corrido bem, você deverá ver a mensagem "Aluno adicionado com sucesso". Abra o index.html no navegador novamente; você deverá ver o novo aluno na lista.

Adicione uma Pitada de JavaScript

Talvez você tenha percebido que ao enviar o formulário o navegador navega para outra página. Esse é o comportamento padrão dos forumlários HTML. Nós podemos prevenir esse comportamento com JavaScript no frontend.

Adicione o código a seguir ao index.html.

<script>
  const form = document.querySelector("form");
  form.addEventListener("submit", async (event) => {
    // A linha abaixo previne o comportamento padrão do formulário, fazendo
    // assim com que a página não mude e os dados não sejam enviados.
    event.preventDefault();

    // Agora precisamos enviar os dados ao servidor manualmente.
    const formData = new FormData(form);
    const response = await fetch("http://localhost:3000/add-student", {
      method: "POST",
      body: new URLSearchParams(formData),
      headers: {
        "content-type": "application/x-www-form-urlencoded",
      },
    });
    const message = await response.text();
    alert(message);
  });
</script>

Esse código adiciona um event listener ao formulário que aguarda pelo evento submit. Quando o evento ocorre, o comportamento padrão de envio de dados e navegação é cancelado. Os dados do formulário são enviados por meio do fetch.

fetch é uma ferramenta disponível em navegadores modernos que nos permite enviar pedidos na rede a partir do JavaScript. Veja mais no MDN Web Docs.

Agora, não haverá navegação quando o formulário for enviado. Ao invés disso, você verá a mensagem "Aluno adicionado com sucesso" em um alerta. Bem legal né? Na verdade, nem tanto, por que nós ainda não vemos o estudante recém-cadastrado na lista.

Atualizando a Lista

Para atualizar a lista, nós temos que fazer uma de duas coisas:

  1. Recarregar a página.
  2. Atualizar a lista com JavaScript.

Como programadores, nós podemos fazer melhor que recarregar a página. Vamos então usar JavaScript para atualizar a lista.

Para fazer isso, vamos primeiro atualizar nosso backend para retornar o novo estudante que acabamos de adicionar.

app.post("/add-student", (req, res) => {
  const { name, age } = req.body;
  const student = { name, age: parseInt(age) };
  students.push(student);
  // Retorne o novo estudante. Note que nós estamos chamando `res.json` ao invés
  // de `res.send`. Isso por que nós estamos retornando um objeto JSON.
  return res.json(student);
});

JSON significa JavaScript Object Notation, ou Notação JavaScript de Objetos. É um formato de transmissão e armazenamento de dados leve, abrangentemente utilizado para troca de dados entre servidores e clientes. Ele é fácil de ler já que sua sintaxe é similar à de objetos no JavaScript. Na verdade, a sintaxe JSON é um subset da sintaxe de objetos no JavaScript.

Agora, vamos atualizar o código JavaScript no index.html para adicionar o novo estudante à lista.

// const message = await response.text();
// alert(message);
const student = await response.json();
const list = document.getElementById("students");
const listItem = document.createElement("li");
listItem.innerText = `${student.name} (${student.age})`;
list.appendChild(listItem);

Estamos interpretando a resposta como JSON, não texto. Isso nos permite acessar o nome e a idade do estudante por meio de um objeto. Em seguida nós adicionamos um elemento à lista de alunos. Excelente!

Melhorando a User Experience

Uma última coisa que podemos fazer é limpar o formulário após a submissão. Adicione o código a seguir ao final do event listener.

// ...
list.appendChild(listItem);
// Limpar o formulário
form.reset();

Com essa mudança, o formulário será limpo após o envio dos dados. Essa pequena mudança melhor a experiência dos nossos usuários, permitindo que eles preencham os campos com novos dados sem ter que se preocupar com limpar os campos.

Submissão do formulário

Refatoração

Nosso código está começando a ficar um pouco repetitivo. Vamos ver como melhorar isso um pouco.

Primeiro, vamos criar uma função para adicionar um estudante à lista.

function addStudentToList(student) {
  const list = document.getElementById("students");
  const listItem = document.createElement("li");
  listItem.innerText = `${student.name} (${student.age})`;
  list.appendChild(listItem);
}

Esta função recebe um objeto estudante e o adiciona à lista. Agora, vamos atualizar o event listener para que ele use essa função.

form.addEventListener("submit", async (event) => {
  event.preventDefault();

  const formData = new FormData(form);
  const response = await fetch("http://localhost:3000/add-student", {
    method: "POST",
    body: new URLSearchParams(formData),
    headers: {
      "content-type": "application/x-www-form-urlencoded",
    },
  });
  const student = await response.json();
  addStudentToList(student);
  form.reset();
});

Muito melhor! Separar a lógica de adicionar um estudante à lista em uma função torna nosso código mais fácil de ler e manter.

Também podemos atualizar a lista inicial de estudantes para usar essa função.

fetch("http://localhost:3000/students")
  .then((response) => response.json())
  .then((students) => {
    for (const student of students) {
      addStudentToList(student);
    }
  });

Essa prática de evitar repetições faz parte do princípio KISS. KISS significa "Keep It Simple, Stupid" ou "Mantenha Isso Simples, Idiota". É um princípio de design que afirma que a maioria dos sistemas funciona melhor quando são mantidos simples em vez de complicados. Este princípio é especialmente importante no desenvolvimento de software, onde a complexidade pode levar a bugs e problemas de manutenção.

Conclusão

Nesse post, aprendemos a lidar com submissão de formulários no backend. Nós também aprendemos a cancelar o comportamento padrão dos formulários HTML. Atualizamos a lista de estudantes sem precisar recarregar a página, o que é uma grande melhoria para a experiência dos usuários.

O maior problema com nossa implementação atual é que estamos armazenando os estudantes na memória. Isso significa que, se o servidor reiniciar, todos os estudantes serão perdidos. No próximo post, aprenderemos como armazenar os estudantes em um banco de dados para que eles sejam persistidos, mesmo que o servidor reinicie.

Como de costume, você pode encontrar o código deste post no GitHub