Entendendo como fazer AJAX com a FetchAPI

Sem dúvida fazer um request AJAX foi uma das coisas que eu mais achei legais e que eu mais aprendi do jeito errado no começo da carreira hahaha

Hoje, depois de vários projetos e dando aulas nos cursos que envolvem JavaScript no lado do front end lá na Caelum, uma dúvida que os alunos têm bastante, principalmente quem está começando é: “Como se comunicar com o banco de dados via JavaScript”.

Isso não é possível no browser (só lá no mundo do server com o Node), e isso acaba sendo, normalmente, a deixa para eu falar que existe a técnica do AJAX. Resolvi deixar aqui registrado a resposta para essa pergunta e por isso, hoje vamos ver como fazer isso usando a FetchAPI. Se você já conhece o tema, indique para um amigo que esteja começando nesse mundo e o post possa ajudar \o/

Já vou deixar de antemão o link da MDN explicando o que é e como o fetch funciona: https://developer.mozilla.org/pt-BR/docs/Web/API/Fetch_API/Using_Fetch, a ideia do post é só ser uma versão talvez mais "conversa" de falar sobre o tema :)

Preparando o ambiente

Para esse post é legal você já ter um conhecimento base de JavaScript, noções de o que são arrays, objetos e funções \o

Fundamentando a base da coisa toda

Bom, no curso de React presencial que eu ministro na Caelum a gente faz um twitter com bem mais funcionalidades do que tem nessa imagem aqui embaixo:

Essa versão do projeto é mais simplificada e foi usada inicialmente em um Workshop de React que eu dei :)

Tudo ali é feito só JavaScript com JavaScript no browser (com o React) e os dados vem dessa API aqui http://twitelum-api.herokuapp.com/tweets

Para esses dados virarem a interface bonitinha que vimos ali em cima precisamos de alguma forma copiar e colar o código que está nessa página, só que via JavaScript. O browser já faz isso pra gente através de um request HTTP. Em linhas gerais, é como se via browser quiséssemos acessar o banco que guarda os dados dos tweets:

Infelizmente (ou felizmente), isso não é possível de se fazer diretamente via browser. Pelo forma como ele funciona, nós passamos para ele a URL de um site, com ela em mãos, é gerado um request via o protocolo HTTP ele acontecem as magias exatas para nos trazer os dados.

Nossa requisição vai até um servidor e esse servidor, por sua vez criado em qualquer linguagem de backend, faz o trabalho de acessar o banco e nos fornecer em forma de HTML, XML ou esse formato que vemos aqui ao acessar a twitelum api, o tal do JSON.

Do contrário, todos teríamos que acessar o banco de dados diretamente e isso poderia ser meio perigoso/insano levando em conta segurança.

Esse JSON (json.org), é um formato de dado inspirado no objeto do JavaScript, que é bastante utilizado hoje em dia para trafegar dados para sites, aplicativos mobile entre outros tipos.

Agora, saindo da teoria e indo para a prática, vamos via console tentar fazer essa requisição sem passar uma URL na barra de navegação do browser, e sim fazer o processo via JavaScript, em outras palavras vamos fazer um AJAX (Asynchronous JavaScript and XML):

Mão na massa

Agora vamos abrir o console do chrome, clicando com o botão direito do mouse na tela, depois no inspect e por fim na abinha escrito console:

Feito isso, vamos criar uma variável e chamar a função fetch, que irá nos ajudar no processo de se comunicar com o servidor.

Se olharmos o retorno do console.log, teremos algo assim:

Isso acontece porque a função fetch retorna um tipo de dado chamado Promise. As promises são códigos que rodam assincronamente no JavaScript.

Elas existem para facilitar o trabalho com coisas que demoram muito para serem executadas pois se não fosse isso, pela forma como o JavaScript funciona de só executar uma coisa por vez, esperar a requisição ser terminada para rodar a linha de baixo ia prejudicar a interação do usuário no site.

Para conseguir pegar o dado que vem da promisse, ao invés de salvar em uma variável, devemos colocar na frente do fetch uma chamada de uma função .then() e passar como argumento para ela uma função que irá receber o retorno da requisição que estamos fazendo para o servidor.

Sabemos que nossa requisição deu certo por conta do status vir como 200 (e se você tiver dúvidas sobre os status do http recomendo dar uma olhada nesse site https://httpstatusdogs.com)

Mas se tentarmos acessar o que vem no corpo da requisição nós ainda não temos os tweets :(

Isso acontece porque o .then() que chamamos na frente do fetch() é chamado assim que os dados começam a vir pela rede e chega em nossa máquina, uma requisição pode ter tamanhos variados e formatos de dados que chegam também (Aqui você pode ver outros tipos: https://developer.mozilla.org/pt-BR/docs/Web/API/Body).

Pela rede, todos os dados que trafegam são no formato de texto, e assim é o JSON. Nativamente ele precisa ser convertido para um objeto JavaScript e o fetch() tem um recurso que permite que nós façamos a solicitação dessa conversão que pode demorar de acordo com o tamanho do que vem pela rede, logo isso também é uma promise.

Para converter, basta pegarmos a resposta do servidor e chamar a função .json() que está com ela:

E como as promises (o tipo de dado retornado após executarmos um fetch()) podem ser encadeados, esse código é comumente escrito nesse formato:

E como enviar dados para o servidor via AJAX?

Até agora nós só pegamos dados via o verbo GET do HTTP, existem outras formas pré definidas de se comunicarmos com um servidor e você pode ver todas aqui https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods ou direto na espeficicação https://tools.ietf.org/html/rfc7231#section-4.

Se quisermos criar um tweet, tudo o que precisamos é chamar a função fetch passando um objeto de configuração após a URL que irá receber:

  • method: o método http que queremos utilizar (POST, GET (é o padrão), DELETE …)
  • body: O conteúdo que queremos enviar (que se for um objeto precisa ser convertido para JSON com a função JSON.stringify(), pois sem fazer isso o JavaScript irá fazer um .toString no objeto e o que será enviado pela rede será um [objectObject] )
Exemplo do que é enviado para o servidor se não passarmos o objeto dentro do JSON.stringify
  • headers: E algum header, em nosso caso estamos informando o servidor que irá receber os dados que estamos enviando um JSON.

E como lidar com erros?

No código anterior pegamos o caminho feliz da coisa, em um cenário que você deseje fazer algum tratamento de erros. Como estamos trabalhando com uma promise, caso qualquer erro ocorra você pode lançar um `throw` a qualquer momento em qualquer .then() e o erro irá automaticamente parar no then que deu erro e pular para o .catch() que você pode definir após o último .then():

Espero que tenha gostado do post, em breve trarei mais dicas, se curtiu e quiser saber em primeira mão quando vierem novos conteúdos, me segue no meu twitter e pra acompanhar meus outros posts ta tudo centralizado em meu site pessoal https://mariosouto.com até mais \o