$ sudo teach IT
МОДУЛЬ 10 · УРОК 6

fetch: запросы к API и рендер данных

fetch — встроенный браузерный инструмент для HTTP-запросов. С его помощью JavaScript общается с сервером: загружает данные, отправляет формы, обновляет информацию без перезагрузки страницы. Это основа любого современного веб-приложения.

⏱ ~30 минут 🎓 Средний 🌐 HTTP API

🌐 Базовый fetch — GET запрос

fetch(url) возвращает Promise. Когда сервер ответит — промис выполнится с объектом Response. Но внимание: Response — это не данные! Это объект-обёртка ответа. Чтобы получить JSON, нужно вызвать response.json() — тоже возвращает Promise.

// Цепочка .then()
fetch('https://jsonplaceholder.typicode.com/users/1')
  .then(response => {
    console.log(response.status); // 200
    console.log(response.ok);     // true (если 200-299)
    return response.json();        // распаковываем JSON → ещё один Promise
  })
  .then(user => {
    console.log(user.name);   // Leanne Graham
    console.log(user.email);  // Sincere@april.biz
  })
  .catch(error => {
    console.error('Ошибка сети:', error);
  });

⚠️ Важно! fetch НЕ считает HTTP-ошибки (404, 500) ошибками промиса. Промис отклоняется только при сетевых ошибках (нет интернета, DNS). Ответ 404 — всё равно fulfilled! Поэтому всегда проверяйте response.ok.

🛡️ Правильная обработка ошибок

async function fetchUser(id) {
  try {
    const response = await fetch(
      `https://jsonplaceholder.typicode.com/users/${id}`
    );

    // Проверяем HTTP-статус — fetch сам не бросает ошибку при 404!
    if (!response.ok) {
      throw new Error(`Ошибка HTTP: ${response.status}`);
    }

    const user = await response.json();
    return user;

  } catch (error) {
    // Ловим и сетевые ошибки, и наш throw выше
    console.error('Не удалось загрузить:', error.message);
    return null;
  }
}

// Используем
const user = await fetchUser(1);
if (user) {
  document.querySelector('#name').textContent = user.name;
}

📤 POST запрос — отправка данных

По умолчанию fetch делает GET-запрос. Чтобы отправить данные (POST, PUT, DELETE) — нужно передать второй аргумент с настройками: метод, заголовки и тело запроса.

async function createPost(title, body) {
  const response = await fetch(
    'https://jsonplaceholder.typicode.com/posts',
    {
      method: 'POST',             // HTTP метод
      headers: {
        'Content-Type': 'application/json', // тип тела
      },
      body: JSON.stringify({      // данные — JSON-строка
        title,
        body,
        userId: 1
      })
    }
  );

  if (!response.ok) {
    throw new Error(`Ошибка: ${response.status}`);
  }

  const newPost = await response.json();
  console.log('Создан пост с id:', newPost.id);
  return newPost;
}
GET

Получить данные. По умолчанию. Без тела.

POST

Создать новый ресурс. С телом.

PUT / PATCH

Обновить существующий ресурс.

DELETE

Удалить ресурс.

💻 Полный пример: загрузка и рендер списка

// Загружаем список пользователей и рисуем их на странице
async function renderUsers() {
  const container = document.querySelector('#users-list');

  // Показываем индикатор загрузки
  container.innerHTML = '<p>Загрузка...</p>';

  try {
    const response = await fetch(
      'https://jsonplaceholder.typicode.com/users'
    );

    if (!response.ok) {
      throw new Error(`Ошибка: ${response.status}`);
    }

    const users = await response.json(); // массив пользователей

    // Очищаем лоадер и рисуем пользователей
    container.innerHTML = '';

    users.forEach(user => {
      const card = document.createElement('div');
      card.innerHTML = `
        <h3>${user.name}</h3>
        <p>Email: ${user.email}</p>
        <p>Город: ${user.address.city}</p>
      `;
      container.appendChild(card);
    });

  } catch (error) {
    container.innerHTML = `<p>Ошибка: ${error.message}</p>`;
  }
}

// Вызываем при загрузке страницы
renderUsers();

✅ Итоги урока

  • fetch(url) → Promise → Response → .json() → данные
  • fetch НЕ бросает ошибку при HTTP 404/500 — всегда проверяй response.ok
  • POST-запрос: второй аргумент с method, headers, body
  • Тело POST-запроса — строка: body: JSON.stringify(data)
  • Заголовок 'Content-Type': 'application/json' — обязателен для POST с JSON
  • Паттерн: показать лоадер → fetch → обработать → скрыть лоадер (в finally)
  • jsonplaceholder.typicode.com — бесплатный API для практики без бэкенда

В последнем уроке разберём localStorage — как сохранять данные в браузере без сервера. 🚀

fetch: запросы к API и рендер данных

7 вопросов

GET-запрос с обработкой ошибок

Напишите async функцию fetchData(url), которая делает GET-запрос, проверяет response.ok, и если всё хорошо — возвращает данные в формате JSON. Если response.ok === false — выбрасывает ошибку с HTTP-статусом. Сетевые ошибки тоже должны быть обработаны через try/catch и возвращать null.

POST-запрос с JSON-телом

Напишите async функцию postData(url, data), которая отправляет POST-запрос с JSON-телом. Укажите заголовок Content-Type: application/json. В случае успеха верните ответ сервера как объект. При ошибке — выбросьте исключение с текстом ошибки.