Atualizado: 21/06/2025

Este conteúdo é original e não foi gerado por inteligência artificial.

Criando um Cliente REST com Fetch API em JavaScript

Utilizando o Fetch API em JavaScript, é possível implementar um cliente completo para Web APIs no estilo REST, facilitando a interação com o servidor. A arquitetura REST utiliza métodos HTTP específicos para a comunicação com o servidor:

  • GET para obter dados.
  • POST para adicionar dados.
  • PUT para atualizar dados.
  • DELETE para remover dados.

Vamos explorar como criar um cliente em JavaScript para interagir com uma API.

Criando o Servidor com Node.js

Primeiramente, vamos definir o servidor que representará a Web API. Utilizaremos Node.js para isso. Para processar as requisições, crie um arquivo server.js com o seguinte conteúdo:

const http = require("http");
const fs = require("fs");

// Dados com os quais o cliente irá interagir
const users = [
  { id: 1, name: "Tom", age: 24 },
  { id: 2, name: "Bob", age: 27 },
  { id: 3, name: "Alice", age: 23 },
];

// Função para processar os dados recebidos do cliente
function getReqData(req) {
  return new Promise(async (resolve, reject) => {
    try {
      const buffers = [];
      for await (const chunk of req) {
        buffers.push(chunk);
      }
      const data = JSON.parse(Buffer.concat(buffers).toString());
      resolve(data);
    } catch (error) {
      reject(error);
    }
  });
}

http
  .createServer(async (request, response) => {
    // Obtenção de todos os usuários
    if (request.url === "/api/users" && request.method === "GET") {
      response.end(JSON.stringify(users));
    }
    // Obtenção de um usuário específico por ID
    else if (request.url.match(/\/api\/users\/([0-9]+)/) && request.method === "GET") {
      const id = request.url.split("/")[3];
      const user = users.find((u) => u.id === parseInt(id));
      if (user) {
        response.end(JSON.stringify(user));
      } else {
        response.writeHead(404, { "Content-Type": "application/json" });
        response.end(JSON.stringify({ message: "Usuário não encontrado" }));
      }
    }
    // Exclusão de um usuário por ID
    else if (request.url.match(/\/api\/users\/([0-9]+)/) && request.method === "DELETE") {
      const id = request.url.split("/")[3];
      const userIndex = users.findIndex((u) => u.id === parseInt(id));
      if (userIndex > -1) {
        const user = users.splice(userIndex, 1)[0];
        response.end(JSON.stringify(user));
      } else {
        response.writeHead(404, { "Content-Type": "application/json" });
        response.end(JSON.stringify({ message: "Usuário não encontrado" }));
      }
    }
    // Adição de um novo usuário
    else if (request.url === "/api/users" && request.method === "POST") {
      try {
        const userData = await getReqData(request);
        const user = { name: userData.name, age: userData.age };
        const id = Math.max.apply(
          Math,
          users.map((u) => u.id)
        );
        user.id = id + 1;
        users.push(user);
        response.end(JSON.stringify(user));
      } catch (error) {
        response.writeHead(400, { "Content-Type": "application/json" });
        response.end(JSON.stringify({ message: "Solicitação inválida" }));
      }
    }
    // Atualização de um usuário
    else if (request.url === "/api/users" && request.method === "PUT") {
      try {
        const userData = await getReqData(request);
        const user = users.find((u) => u.id === parseInt(userData.id));
        if (user) {
          user.age = userData.age;
          user.name = userData.name;
          response.end(JSON.stringify(user));
        } else {
          response.writeHead(404, { "Content-Type": "application/json" });
          response.end(JSON.stringify({ message: "Usuário não encontrado" }));
        }
      } catch (error) {
        response.writeHead(400, { "Content-Type": "application/json" });
        response.end(JSON.stringify({ message: "Solicitação inválida" }));
      }
    } else if (request.url === "/" || request.url === "/index.html") {
      fs.readFile("index.html", (error, data) => response.end(data));
    } else {
      response.writeHead(404, { "Content-Type": "application/json" });
      response.end(JSON.stringify({ message: "Recurso não encontrado" }));
    }
  })
  .listen(3000, () => console.log("Servidor iniciado em http://localhost:3000"));

Analise do Código

Vamos analisar este código de forma geral. Primeiro, são definidos os dados com os quais o cliente irá trabalhar:

const users = [
  { id: 1, name: "Tom", age: 24 },
  { id: 2, name: "Bob", age: 27 },
  { id: 3, name: "Alice", age: 23 },
];

Para simplificação, os dados são definidos como um array comum de objetos, mas em situações reais esses dados geralmente são extraídos de um banco de dados.

Em seguida, é definida a função getReqData(), que extrai os dados enviados pelo cliente na requisição e os converte para o formato JSON (assumindo que o cliente enviará os dados em JSON):

function getReqData(req) {
  return new Promise(async (resolve, reject) => {
    try {
      const buffers = [];
      for await (const chunk of req) {
        buffers.push(chunk);
      }
      const data = JSON.parse(Buffer.concat(buffers).toString());
      resolve(data);
    } catch (error) {
      reject(error);
    }
  });
}

O resultado da função é definido como uma promise. Se os dados forem analisados com sucesso, a promise retorna o objeto parseado. Caso ocorra um erro, uma mensagem de erro é retornada.

Para cada tipo de requisição, é definido um cenário específico.

Quando a aplicação recebe uma requisição do tipo GET no endereço "api/users", o seguinte código é executado:

if (request.url === "/api/users" && request.method === "GET") {
  response.end(JSON.stringify(users));
}

Aqui, simplesmente enviamos o array users definido anteriormente.

Quando o cliente solicita um objeto específico por ID em uma requisição GET no endereço "api/users/", o seguinte código é executado:

else if (request.url.match(/\/api\/users\/([0-9]+)/) && request.method === "GET") {
    const id = request.url.split("/")[3];
    const user = users.find((u) => u.id === parseInt(id));
    if (user) {
        response.end(JSON.stringify(user));
    } else {
        response.writeHead(404, { "Content-Type": "application/json" });
        response.end(JSON.stringify({ message: "Usuário não encontrado" }));
    }
}

Nesse caso, precisamos encontrar o usuário no array pelo ID e, se não for encontrado, retornamos um código de status 404 com uma mensagem de erro em JSON.

Ao receber uma requisição DELETE no endereço "/api/users/", encontramos o índice do objeto no array e, se encontrado, o removemos do array e enviamos a resposta ao cliente:

else if (request.url.match(/\/api\/users\/([0-9]+)/) && request.method === "DELETE") {
    const id = request.url.split("/")[3];
    const userIndex = users.findIndex((u) => u.id === parseInt(id));
    if (userIndex > -1) {
        const user = users.splice(userIndex, 1)[0];
        response.end(JSON.stringify(user));
    } else {
        response.writeHead(404, { "Content-Type": "application/json" });
        response.end(JSON.stringify({ message: "Usuário não encontrado" }));
    }
}

Se o objeto não for encontrado, retornamos um código de status 404.

Ao receber uma requisição POST no endereço "/api/users", usamos a função getReqData() para extrair os dados da requisição:

else if (request.url === "/api/users" && request.method === "POST") {
    try {
        const userData = await getReqData(request);
        const user = { name: userData.name, age: userData.age };
        const id = Math.max.apply(Math, users.map(u => u.id)) + 1;
        user.id = id;
        users.push(user);
        response.end(JSON.stringify(user));
    } catch (error) {
        response.writeHead(400, { "Content-Type": "application/json" });
        response.end(JSON.stringify({ message: "Solicitação inválida" }));
    }
}

Como a execução da função pode lançar um erro (por exemplo, ao analisar JSON), todo o código é encapsulado em um bloco try..catch. Após obter os dados, criamos um novo objeto e o adicionamos ao array.

Se a aplicação receber uma requisição PUT, também usamos a função getReqData() para obter os dados enviados pelo cliente. Se o objeto for encontrado no array, atualizamos os dados, caso contrário, enviamos um código de status 404:

else if (request.url === "/api/users" && request.method === "PUT") {
    try {
        const userData = await getReqData(request);
        const user = users.find((u) => u.id === parseInt(userData.id));
        if (user) {
            user.age = userData.age;
            user.name = userData.name;
            response.end(JSON.stringify(user));
        } else {
            response.writeHead(404, { "Content-Type": "application/json" });
            response.end(JSON.stringify({ message: "Usuário não encontrado" }));
        }
    } catch (error) {
        response.writeHead(400, { "Content-Type": "application/json" });
        response.end(JSON.stringify({ message: "Solicitação inválida" }));
    }
}

Dessa forma, definimos uma API básica. Agora, vamos adicionar o código do cliente.

Definindo o Cliente

Ao acessar a raiz da aplicação web ou o endereço /index.html, o servidor retornará o arquivo index.html. Portanto, na mesma pasta do arquivo do servidor, defina um arquivo index.html com o seguinte código:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width" />
    <title>Programício</title>
    <style>
      tr {
        height: 30px;
      }
      td,
      th {
        min-width: 40px;
        text-align: left;
      }
      a {
        cursor: pointer;
        padding: 5px;
        text-decoration: underline;
        color: navy;
      }
      input {
        width: 180px;
      }
    </style>
  </head>
  <body>
    <h2>Lista de Usuários</h2>
    <form name="userForm">
      <p>
        <label for="name">Nome:</label><br />
        <input name="name" />
      </p>
      <p>
        <label for="age">Idade:</label><br />
        <input name="age" type="number" min="1" max="110" />
      </p>
      <p>
        <button type="submit">Salvar</button>
        <button type="reset">Resetar</button>
      </p>
    </form>
    <table>
      <thead>
        <tr>
          <th>Id</th>
          <th>Nome</th>
          <th>Idade</th>
          <th></th>
        </tr>
      </thead>
      <tbody></tbody>
    </table>

    <script>
      let userId = 0; // Identificador do usuário que está sendo editado
      const userForm = document.forms["userForm"]; // Formulário de entrada

      // Função para obter todos os usuários
      async function getUsers() {
        const response = await fetch("/api/users", {
          method: "GET",
          headers: { Accept: "application/json" },
        });
        if (response.ok === true) {
          const users = await response.json();
          const rows = document.querySelector("tbody");
          users.forEach((user) => rows.append(row(user)));
        }
      }

      // Função para obter um usuário específico
      async function getUser(id) {
        const response = await fetch(`/api/users/${id}`, {
          method: "GET",
          headers: { Accept: "application/json" },
        });
        if (response.ok === true) {
          const user = await response.json();
          userId = user.id;
          userForm.elements["name"].value = user.name;
          userForm.elements["age"].value = user.age;
        }
      }

      // Função para criar um novo usuário
      async function createUser(userName, userAge) {
        const response = await fetch("/api/users", {
          method: "POST",
          headers: { Accept: "application/json", "Content-Type": "application/json" },
          body: JSON.stringify({
            name: userName,
            age: parseInt(userAge, 10),
          }),
        });
        if (response.ok === true) {
          const user = await response.json();
          reset();
          document.querySelector("tbody").append(row(user));
        }
      }

      // Função para editar um usuário
      async function editUser(userId, userName, userAge) {
        const response = await fetch("/api/users", {
          method: "PUT",
          headers: { Accept: "application/json", "Content-Type": "application/json" },
          body: JSON.stringify({
            id: userId,
            name: userName,
            age: parseInt(userAge, 10),
          }),
        });
        if (response.ok === true) {
          const user = await response.json();
          reset();
          document.querySelector(`tr[data-rowid='${user.id}']`).replaceWith(row(user));
        }
      }

      // Função para deletar um usuário
      async function deleteUser(id) {
        const response = await fetch(`/api/users/${id}`, {
          method: "DELETE",
          headers: { Accept: "application/json" },
        });
        if (response.ok === true) {
          const user = await response.json();
          document.querySelector(`tr[data-rowid='${user.id}']`).remove();
        }
      }

      // Função para resetar o formulário
      function reset() {
        userForm.reset();
        userId = 0;
      }

      // Função para criar uma linha na tabela
      function row(user) {
        const tr = document.createElement("tr");
        tr.setAttribute("data-rowid", user.id);

        const idTd = document.createElement("td");
        idTd.append(user.id);
        tr.append(idTd);

        const nameTd = document.createElement("td");
        nameTd.append(user.name);
        tr.append(nameTd);

        const ageTd = document.createElement("td");
        ageTd.append(user.age);
        tr.append(ageTd);

        const linksTd = document.createElement("td");

        const editLink = document.createElement("a");
        editLink.setAttribute("data-id", user.id);
        editLink.append("Editar");
        editLink.addEventListener("click", async (e) => {
          e.preventDefault();
          await getUser(user.id);
        });
        linksTd.append(editLink);

        const removeLink = document.createElement("a");
        removeLink.setAttribute("data-id", user.id);
        removeLink.append("Deletar");
        removeLink.addEventListener("click", async (e) => {
          e.preventDefault();
          await deleteUser(user.id);
        });

        linksTd.append(removeLink);
        tr.appendChild(linksTd);

        return tr;
      }

      // Evento de reset do formulário
      userForm.addEventListener("reset", (e) => reset());

      // Evento de submit do formulário
      userForm.addEventListener("submit", (e) => {
        e.preventDefault();
        const name = userForm.elements["name"].value;
        const age = userForm.elements["age"].value;

        if (userId === 0) {
          createUser(name, age);
        } else {
          editUser(userId, name, age);
        }
      });

      // Carregar os usuários ao carregar a página
      getUsers();
    </script>
  </body>
</html>

Explicação do Código

A lógica principal está no código JavaScript. Inicialmente, definimos dados globais:

let userId = 0; // Identificador do usuário que está sendo editado
const userForm = document.forms["userForm"]; // Formulário de entrada

A constante userForm representa o formulário para adicionar ou editar um usuário. A variável userId rastreia o identificador do usuário carregado. Se for igual a 0, significa que um novo usuário está sendo criado. Por padrão, ao carregar a página, essa variável é 0, indicando que nenhum usuário está carregado no formulário. Se userId não for 0, um usuário foi carregado previamente através da função getUser, e estamos prontos para editar esse usuário.

Ao carregar a página, obtemos todos os usuários do banco de dados usando a função getUsers:

async function getUsers() {
  const response = await fetch("/api/users", {
    method: "GET",
    headers: { Accept: "application/json" },
  });
  if (response.ok === true) {
    const users = await response.json();
    const rows = document.querySelector("tbody");
    users.forEach((user) => rows.append(row(user)));
  }
}

Para adicionar linhas na tabela, usamos a função row, que retorna uma linha com links para editar e deletar o usuário.

A função getUser obtém o usuário do servidor e preenche o formulário com os dados:

async function getUser(id) {
  const response = await fetch(`/api/users/${id}`, {
    method: "GET",
    headers: { Accept: "application/json" },
  });
  if (response.ok === true) {
    const user = await response.json();
    userId = user.id;
    userForm.elements["name"].value = user.name;
    userForm.elements["age"].value = user.age;
  }
}

Se userId for 0, a função createUser envia os dados em uma requisição POST:

async function createUser(userName, userAge) {
  const response = await fetch("/api/users", {
    method: "POST",
    headers: { Accept: "application/json", "Content-Type": "application/json" },
    body: JSON.stringify({
      name: userName,
      age: parseInt(userAge, 10),
    }),
  });
  if (response.ok === true) {
    const user = await response.json();
    reset();
    document.querySelector("tbody").append(row(user));
  }
}

Se um usuário já foi carregado no formulário, a função editUser envia uma requisição PUT para atualizar os dados:

async function editUser(userId, userName, userAge) {
  const response = await fetch("/api/users", {
    method: "PUT",
    headers: { Accept: "application/json", "Content-Type": "application/json" },
    body: JSON.stringify({
      id: userId,
      name: userName,
      age: parseInt(userAge, 10),
    }),
  });
  if (response.ok === true) {
    const user = await response.json();
    reset();
    document.querySelector(`tr[data-rowid='${user.id}']`).replaceWith(row(user));
  }
}

Executando o Servidor

Execute o arquivo do servidor com o comando node server.js:

C:\app>node server.js
Servidor iniciado em http://localhost:3000

O servidor Node.js com a API para a função fetch em JavaScript será iniciado. Acesse "http://localhost:3000" no navegador para gerenciar os usuários armazenados no arquivo JSON.

REST e API e função fetch em JavaScript

Política de Privacidade

Copyright © www.programicio.com Todos os direitos reservados

É proibida a reprodução do conteúdo desta página sem autorização prévia do autor.

Contato: programicio@gmail.com