Fetch API в Javascript

Fetch API используется для выполнения ajax-запросов, для вызова API или выборки удаленного ресурса или получения HTML-файла с сервера.

fetch api

Базовый синтаксис Fetch API

Допустим, нужно получить список сообщений из API https://jsonplaceholder.typicode.com/posts. Во-первых, следует передать этот URL в метод fetch() в качестве аргумента.

fetch('https://jsonplaceholder.typicode.com/posts');

Метод fetch() возвращает Promise. Поэтому ответы API нужно обрабатывать с использованием then() и catch().

fetch('https://jsonplaceholder.typicode.com/posts')
  .then(function (response) {
  // API вернул результат
  console.log('success!', response);
}).catch(function (err) {
  // Что-то пошло не так
  console.warn('Ошибка получения.');
  console.log(err);
});

Посмотрите пример.

Посмотрим на ответ в консоли: сразу можно обратить внимание, в response.body нет JSON. Это – ReadableStream.

Fetch API использует потоки. Чтобы получить данные из API в виде объекта JSON, можно использовать оригинальный метод Fetch API: json().

fetch('https://jsonplaceholder.typicode.com/posts')
  .then(function (response) {
  // API вернул результат
  return response.json();
}).then(function (data) {
  // Это уже JSON
  console.log(data);
}).catch(function (err) {
  // Что-то пошло не так
  console.warn('Ошибка получения.');
  console.log(err);
});

Посмотрите, теперь тут нормальный JSON.

Обработка ошибок для Fetch API

Fetch API обрабатывает ошибки с помощью метода catch(), потому что он возвращает Promise.

Однако, Promise отклоняется и вызывает метод catch() только в случае сбоя. Если вернулся ответ от сервера, даже в случае с ошибками 404 или 500, будут работать методы then().

Чтобы пофиксить такое поведение, можно использовать свойство ok в response, который возвращает Promise.

Если у свойства response.ok значение true, вернём response.json(). Если нет, то вернём отклоненный объект Promise и передадим в нём ответ, чтобы вызвать метод catch().

fetch('https://jsonplaceholder.typicode.com/postsQQQQ')
  .then(function (response) {
  // API вернул результат
  if (response.ok) {
    return response.json();
  } else {
    console.log('Это не 200OK')
    return Promise.reject(response);
  }
}).then(function (data) {
  // Это уже JSON
  console.log(data);
}).catch(function (err) {
  // Что-то пошло не так
  console.warn('Ошибка получения.');
  console.log(err);
});

Так лучше обрабатывать ошибки в методе Fetch.

В этом примере умышленно искажён URL, он вернёт 404 ошибку, чтобы продемонстрировать отклонение Promise вручную для принудительного вызова метода catch().

То же самое можно делать с помощью XHR

Обработчик onreadystatechange в XHR тоже выполняется независимо от того, был ответ успешным или нет. Здесь тоже нужно проверять, находится ли ответ между 200 и 300, прежде чем работать с ним.

xhr.onreadystatechange = function () {
  // Вернём, когда работа метода завершится
  if (xhr.readyState !== 4) return;
    // обработаем ответ
    if (xhr.status >= 200 && xhr.status < 300) {
      // Ответ нормальный
      console.log('success', JSON.parse(xhr.responseText));
    } else {
      // Ответ плохой
      console.log('error', xhr);
  }
};

У Fetch API код получился намного чище, сравните.

Создание других типов запросов

По умолчанию Fetch API выполняет GET-запросы. Допустим, нужно сделать POST-запрос для публикации новой статьи через API. Методу fetch() надо в этом случае передавать второй аргумент, который можно использовать для передачи объекта с параметрами.

fetch('https://jsonplaceholder.typicode.com/posts', {
  method: 'POST'
}).then(function (response) {
  // API вернул результат
  if (response.ok) {
    return response.json();
  } else {
    console.log('Это не 200OK')
    return Promise.reject(response);
  }
}).then(function (data) {
  // Это уже JSON
  console.log(data);
}).catch(function (err) {
  // Что-то пошло не так
  console.warn('Ошибка получения.');
  console.log(err);
});

Для определенных типов запросов может понадобиться передавать данные вместе с запросом. Это можно сделать с помощью свойства body в объекте параметров.

fetch('https://jsonplaceholder.typicode.com/posts', {
  method: 'POST',
  body: 'title=' + encodeURIComponent('Заголовок') +
        '&body=' + encodeURIComponent('Текст статьи')
}).then(function (response) {
  // API вернул результат
  if (response.ok) {
    return response.json();
  } else {
    console.log('Это не 200OK')
    return Promise.reject(response);
  }
}).then(function (data) {
  // Это уже JSON
  console.log(data);
}).catch(function (err) {
  // Что-то пошло не так
  console.warn('Ошибка получения.');
  console.log(err);
});

Установка заголовков с помощью Fetch API

Еще одна распространенная вещь, которую может потребоваться сделать, установить для запроса заголовки и другие свойства. Это также можно сделать с помощью объекта параметров.

fetch('https://jsonplaceholder.typicode.com/posts', {
  method: 'POST',
  body: 'title=' + encodeURIComponent('Заголовок') +
        '&body=' + encodeURIComponent('Текст статьи'),
  headers: {
    'Content-Type': 'application/json'
  },
  referrer: 'no-referrer'
}).then(function (response) {
  // API вернул результат
  if (response.ok) {
    return response.json();
  } else {
    console.log('Это не 200OK')
    return Promise.reject(response);
  }
}).then(function (data) {
  // Это уже JSON
  console.log(data);
}).catch(function (err) {
  // Что-то пошло не так
  console.warn('Ошибка получения.');
  console.log(err);
});

Демка

Здесь можно поэкспериментировать с кросс-доменными запросами (CORS).

See this code cors fetch on x.xhtml.ru.