Introdução a fetch()

fetch() permite fazer solicitações de rede semelhantes a XMLHttpRequest (XHR). A principal diferença é que a API Fetch usa promessas, que tem uma API mais simples para ajudar a evitar os callbacks complicados na API XMLHttpRequest.

Compatibilidade com navegadores

  • 42
  • 14
  • 39
  • 10.1

Origem

Caso você nunca tenha usado promessas em JavaScript, confira a Introdução às promessas do JavaScript.

Solicitação básica de busca

Veja um exemplo implementado com XMLHttpRequest e depois com fetch. Queremos solicitar um URL, receber uma resposta e analisá-lo como JSON.

XMLHttpRequest

Um XMLHttpRequest precisa de dois listeners para processar os casos de sucesso e de erro, além de uma chamada para open() e send(). Exemplo de documentos do MDN

function reqListener() {
    var data = JSON.parse(this.responseText);
    console.log(data);
}

function reqError(err) {
    console.log('Fetch Error :-S', err);
}

var oReq = new XMLHttpRequest();
oReq.onload = reqListener;
oReq.onerror = reqError;
oReq.open('get', './api/some.json', true);
oReq.send();

Busca

Nossa solicitação de busca é semelhante a esta:

fetch('./api/some.json')
  .then(
  function(response) {
    if (response.status !== 200) {
      console.log('Looks like there was a problem. Status Code: ' +
        response.status);
      return;
    }

    // Examine the text in the response
    response.json().then(function(data) {
      console.log(data);
    });
  }
  )
  .catch(function(err) {
    console.log('Fetch Error :-S', err);
  });

A solicitação fetch() precisa apenas de uma chamada para fazer o mesmo trabalho que o exemplo XHR. Para processar a resposta, primeiro verificamos se o status é 200 e, em seguida, analisamos a resposta como JSON. A resposta a uma solicitação fetch() é um objeto Stream, o que significa que, depois de chamar o método json(), uma promessa é retornada. O stream ocorre de forma assíncrona.

Metadados de resposta

O exemplo anterior mostrou o status do objeto Response e como analisar a resposta como JSON. Veja como processar outros metadados que talvez você queira acessar, como cabeçalhos:

fetch('users.json').then(function(response) {
    console.log(response.headers.get('Content-Type'));
    console.log(response.headers.get('Date'));

    console.log(response.status);
    console.log(response.statusText);
    console.log(response.type);
    console.log(response.url);
});

Tipos de resposta

Quando fazemos uma solicitação de busca, a resposta recebe um response.type de "basic", "cors" ou "opaque". Esses types mostram a origem do recurso e podem ser usados para determinar como tratar o objeto de resposta.

Quando o navegador solicita um recurso na mesma origem, a resposta tem um tipo basic com restrições sobre o que você pode ver na resposta.

Se uma solicitação for feita para um recurso em outra origem e essa origem retornar cabeçalhos CORs, o tipo será cors. As respostas cors são semelhantes às respostas basic, mas restringem os cabeçalhos que você pode ver para Cache-Control, Content-Language, Content-Type, Expires, Last-Modified e Pragma.

As respostas opaque vêm de uma origem diferente que não retorna cabeçalhos CORS. Com uma resposta opaca, não é possível ler os dados retornados nem ver o status da solicitação, o que significa que não é possível verificar se ela foi bem-sucedida.

É possível definir um modo para uma solicitação de busca, de modo que apenas determinados tipos de solicitação sejam resolvidos. Os modos que podem ser configurados são os seguintes:

  • same-origin só é bem-sucedido para solicitações de recursos na mesma origem e rejeita todas as outras solicitações.
  • cors permite solicitações de recursos na mesma origem e em outras origens que retornam os cabeçalhos CORs apropriados.
  • cors-with-forced-preflight executa uma verificação de simulação antes de fazer qualquer solicitação.
  • no-cors destina-se a fazer solicitações para outras origens que não têm cabeçalhos CORS e resultar em uma resposta opaque, mas, conforme declarado, isso não é possível no escopo global da janela no momento.

Para definir o modo, adicione um objeto de opções como o segundo parâmetro na solicitação fetch e defina o modo nesse objeto:

fetch('http://some-site.com/cors-enabled/some.json', {mode: 'cors'})
    .then(function(response) {
    return response.text();
    })
    .then(function(text) {
    console.log('Request successful', text);
    })
    .catch(function(error) {
    log('Request failed', error)
    });

Encadeamento de promessas

Um dos melhores recursos das promessas é a capacidade de encadeá-las. Para fetch(), isso permite compartilhar lógica entre solicitações de busca.

Se você estiver trabalhando com uma API JSON, será necessário verificar o status e analisar o JSON para cada resposta. É possível simplificar o código definindo o status e a análise JSON em funções separadas que retornam promessas e use a solicitação de busca para processar apenas os dados finais e o caso do erro.

function status(response) {
    if (response.status >= 200 && response.status < 300) {
    return Promise.resolve(response)
    } else {
    return Promise.reject(new Error(response.statusText))
    }
}

function json(response) {
    return response.json()
}

fetch('users.json')
    .then(status)
    .then(json)
    .then(function(data) {
    console.log('Request succeeded with JSON response', data);
    }).catch(function(error) {
    console.log('Request failed', error);
    });

Neste exemplo, definimos uma função status que verifica a response.status e retorna uma promessa resolvida como Promise.resolve() ou uma promessa rejeitada como Promise.reject(). Esse é o primeiro método chamado na cadeia fetch().

Se a promessa for resolvida, o script vai chamar o método json(), que retorna uma segunda promessa da chamada response.json() e cria um objeto contendo o JSON analisado. Se a análise falhar, a promessa será rejeitada e a instrução de captura será executada.

Essa estrutura permite compartilhar a lógica em todas as solicitações de busca, facilitando a manutenção, a leitura e o teste do código.

Solicitação POST

Às vezes, um app da Web precisa chamar uma API com um método POST e incluir alguns parâmetros no corpo da solicitação. Para fazer isso, defina os parâmetros method e body nas opções fetch():

fetch(url, {
    method: 'post',
    headers: {
        "Content-type": "application/x-www-form-urlencoded; charset=UTF-8"
    },
    body: 'foo=bar&lorem=ipsum'
    })
    .then(json)
    .then(function (data) {
    console.log('Request succeeded with JSON response', data);
    })
    .catch(function (error) {
    console.log('Request failed', error);
    });

Enviar credenciais com uma solicitação de busca

Para fazer uma solicitação de busca com credenciais como cookies, defina o valor credentials da solicitação como "include":

fetch(url, {
    credentials: 'include'
})