Requisições, Fetch e Promises
A API fetch
é uma interface JavaScript moderna para a realização de requisições HTTP, como solicitar recursos de um servidor. Ela é a evolução da antiga XMLHttpRequest
e oferece uma abordagem mais poderosa e flexível, além de ter uma sintaxe mais limpa e fácil de entender. Vamos desmembrar os conceitos:
Promises
Antes de nos aprofundarmos em fetch
, é importante entender o conceito de "Promises" (Promessas). Uma "Promise" é um objeto que representa a eventual conclusão (ou falha) de uma operação assíncrona e seu valor resultante. Em termos simples, é uma maneira de lidar com operações assíncronas de maneira mais gerenciável e menos propensa a erros do que as tradicionais funções de callback.
Uma "Promise" pode estar em um de três estados:
- Pending (Pendente): Estado inicial, não preenchido nem rejeitado.
- Fulfilled (Realizada): Significa que a operação foi concluída com sucesso.
- Rejected (Rejeitada): Significa que a operação falhou.
Promises têm um método chamado .then()
, que recebe uma função callback e retorna um "objeto-promessa". Não é um retorno dos dados, é a promessa do retorno destes dados.
Assim, podemos escrever o código do que irá acontecer em seguida, com os dados recebidos pela Promise, e o JavaScript vai aguardar a resolução da Promise sem pausar o fluxo do programa.
O resultado pode ou não estar pronto ainda, e não há forma de pegar o valor de uma Promise de modo síncrono; Só é possível requisitar à Promise que execute uma função quando o resultado estiver disponível - seja ele o que foi solicitado (os dados da API, por exemplo), ou uma mensagem de erro caso algo tenha dado errado com a requisição (o servidor pode estar fora do ar, por exemplo).
No exemplo acima: ao iniciarmos uma cadeia de promessas - no caso, para fazer uma requisição HTTP - enquanto a resposta está pendente ela retorna um Promise object
. O objeto, por sua vez, define uma instância do método .then()
. Ao invés de passar o retorno da função callback diretamente para a função inicial, ela é passada para .then()
. Quando o resultado da requisição HTTP chega, o corpo da requisição é convertido para JSON e este valor convertido é passado para o próximo método .then()
.
A cadeia de funções fetch().then().then()
não significa que há múltiplas funções callbacks sendo usadas com o mesmo objeto de resposta, e sim que cada instância de .then()
retorna, por sua vez, um new Promise()
. Toda a cadeia é lida de forma síncrona na primeira execução, e em seguida executada de forma assíncrona.
Fetch
Agora, vamos ao fetch
. A função fetch()
inicia o processo de "buscar" um recurso da rede. Ela retorna uma "Promise" que resolve com o objeto Response
representando a resposta a sua solicitação, seja ela bem-sucedida ou não. Como fetch
é baseado em "Promises", ele utiliza os métodos .then()
e .catch()
para lidar com os valores resolvidos ou rejeitados.
Aqui está a estrutura básica de como fetch
é utilizado:
fetch('url-aqui') // Passo 1: Iniciar uma nova requisição para a URL especificada. .then(response => { // Passo 2: Quando a "Promise" é resolvida, receber um objeto "Response". if (!response.ok) { // Verificar se a resposta foi bem-sucedida. throw new Error('Erro na rede ao tentar buscar recurso.'); } return response.json(); // Se bem-sucedida, ler e parsear o JSON ou qualquer outro tipo de dado. }) .then(data => { // Passo 3: Trabalhar com os dados recebidos (agora no formato JavaScript). console.log(data); }) .catch(error => { // Passo 4: Capturar qualquer erro que tenha ocorrido durante a requisição. console.error('Houve um problema com a operação fetch:', error); });
Explicando o processo:
- Iniciando uma Fetch Request:
fetch('url')
retorna uma "Promise". O JavaScript continuará executando outro código enquanto espera que a promessa seja resolvida. - Manipulando a resposta: O método
.then()
é usado para especificar o que fazer com a resposta. Ele aceita um callback com a resposta. No entanto, esta resposta é um objetoResponse
do stream, e para consumir o corpo da resposta em um tipo específico (como JSON), você precisa usar métodos específicos do objetoResponse
, como.json()
. Este método também retorna uma "Promise", porque ler o stream pode ser uma operação que leva tempo. - Usando o resultado: Uma vez que os dados foram parseados (por exemplo, via
.json()
), você pode usar outro.then()
para trabalhar com os dados no formato JavaScript. - Capturando erros: Se algo der errado na solicitação (como problemas de rede, resposta inválida, etc.),
.catch()
é executado, permitindo que você capture o erro e decida o que fazer com ele (como informar ao usuário).
Benefícios e Características
- Sintaxe Limpa:
fetch
oferece uma maneira mais limpa de lidar com requisições AJAX, especialmente quando comparado com a antigaXMLHttpRequest
. - Manuseio de Erro: Com
fetch
, você tem um controle mais granular sobre o tratamento de erros. Por exemplo, até mesmo respostas HTTP 404 ou 500 não são consideradas erros de rede e não resultarão em umcatch
. Em vez disso, ele trata qualquer resposta como um sucesso, desde que a requisição tenha recebido uma resposta. - Flexibilidade:
fetch
é muito mais flexível e modular do que as abordagens antigas, permitindo que você escolha quais requisições e respostas manipular, em vez de ter que receber o pacote completo.
No entanto, é importante notar que, embora fetch
seja fantástico, ele não é suportado em navegadores mais antigos. Em projetos que requerem compatibilidade com navegadores mais antigos, bibliotecas como Axios ou o pollyfill para fetch
podem ser utilizadas.
{ "socios": [ { "id": 1, "nome": "João Silva", "plano": "Bronze", "telefone": "1122334455", "email": "[email protected]", "status": "ativo" }, { "id": 2, "nome": "Mariana Pereira", "plano": "Ouro", "telefone": "1122334466", "email": "[email protected]", "status": "ativo" }, { "id": 3, "nome": "Lucas Moura", "plano": "Prata", "telefone": "1122334477", "email": "[email protected]", "status": "desativo" }, { "id": 4, "nome": "Patricia Santos", "plano": "Bronze", "telefone": "1122334488", "email": "[email protected]", "status": "ativo" }, { "id": 5, "nome": "Roberto Almeida", "plano": "Ouro", "telefone": "1122334499", "email": "[email protected]", "status": "desativo" }, { "id": 6, "nome": "Camila Dias", "plano": "Prata", "telefone": "1122334500", "email": "[email protected]", "status": "ativo" }, { "id": 7, "nome": "Carlos Oliveira", "plano": "Bronze", "telefone": "1122334511", "email": "[email protected]", "status": "ativo" } ] }