Урок 5 из 8 · 25 мин · обновлено
Данные с сервера: API, JSON и запросы fetch
Как frontend получает данные от backend: что такое API и JSON, как отправить запрос с помощью fetch, показать данные на странице и не забыть про загрузку и ошибки.
API: договорённость с backend
Меню «Зерна» меняется каждый сезон, и цены хранятся в базе на сервере. Frontend не знает их заранее — он запрашивает их у backend через API.
API — договорённость: «по адресу /api/menu сервер отдаёт список напитков в таком-то виде». Backend-разработчик описывает API, frontend-разработчик его использует. Если формат меняется, обе стороны должны знать об этом заранее.
JSON
Данные обычно приходят в формате JSON — текст, похожий на объекты JavaScript:
[
{ "id": 1, "name": "Капучино", "price": 220, "available": true },
{ "id": 2, "name": "Латте", "price": 250, "available": true },
{ "id": 3, "name": "Раф", "price": 290, "available": false }
]
Это массив из трёх напитков. У каждого — номер, название, цена и признак, есть ли он сейчас в наличии.
Запрос fetch
Чтобы получить данные, используют встроенную функцию fetch:
async function loadMenu() {
const response = await fetch('/api/menu');
const drinks = await response.json();
console.log(drinks.length);
}
loadMenu();
3
fetchотправляет запрос на сервер;awaitждёт ответа и не замораживает страницу — пользователь может прокручивать и нажимать;response.json()превращает текст ответа в массив объектов.
Показываем меню
Теперь выведем напитки на страницу, пропуская те, что закончились:
async function loadMenu() {
const response = await fetch('/api/menu');
const drinks = await response.json();
const list = document.querySelector('.menu');
for (const drink of drinks.filter(d => d.available)) {
const item = document.createElement('li');
item.textContent = `${drink.name} — ${drink.price} ₽`;
list.append(item);
}
}
На странице появятся две строки: «Капучино — 220 ₽» и «Латте — 250 ₽».
Мы используем textContent, а не innerHTML. Если в названии от сервера по ошибке или злому умыслу окажется HTML-код, textContent покажет его как текст, а innerHTML встроит в страницу. Почему это опасно, разобрано в уроке об уязвимостях курса «Специалист по кибербезопасности».
Загрузка и ошибки
У каждого запроса три состояния, и интерфейс должен показать все:
| Состояние | Что видит пользователь |
|---|---|
| Загрузка | «Загружаем меню…» или заготовки карточек |
| Успех | Список напитков |
| Ошибка | «Не получилось загрузить меню» и кнопка «Попробовать снова» |
async function loadMenu() {
const status = document.querySelector('.status');
status.textContent = 'Загружаем меню…';
try {
const response = await fetch('/api/menu');
if (!response.ok) throw new Error(`Код ответа ${response.status}`);
const drinks = await response.json();
status.textContent = '';
// показываем drinks, как выше
} catch (error) {
status.textContent = 'Не получилось загрузить меню. Проверьте интернет и попробуйте снова.';
}
}
Новички часто делают только «успех» — и пользователь с медленным интернетом видит пустую страницу. Посмотреть, какие запросы отправляет страница и что приходит в ответ, можно во вкладке Network инструментов разработчика. Подробнее о работе с API — в курсе «Postman и API».
Попробуйте сами. Сервер «Зерна» по адресу /api/orders/42 отдаёт заказ: { "id": 42, "status": "cooking", "minutes": 4 }. Напишите функцию, которая показывает на странице «Заказ №42 готовится, осталось 4 мин», а при ошибке — понятное сообщение.
Пример ответа
async function showOrder(id) {
const box = document.querySelector('.order-status');
box.textContent = 'Проверяем заказ…';
try {
const response = await fetch(`/api/orders/${id}`);
if (!response.ok) throw new Error(response.status);
const order = await response.json();
box.textContent = order.status === 'cooking'
? `Заказ №${order.id} готовится, осталось ${order.minutes} мин`
: `Заказ №${order.id} готов`;
} catch (error) {
box.textContent = 'Не получилось узнать статус заказа. Попробуйте обновить страницу.';
}
}
showOrder(42);
Мини-тест · 4 вопроса
Проверьте себя
Выберите вариант, который кажется вам правильным. В конце вы увидите свой результат и объяснение к каждому вопросу.
-
Что такое API в веб-разработке?
Backend публикует адреса вроде /api/menu и описывает, что по ним приходит. Frontend отправляет запросы по этим адресам.
-
Для чего нужен await перед fetch?
Запрос к серверу занимает время. await дожидается ответа, а страница в это время продолжает реагировать на действия пользователя.
-
Сервер не ответил. Что должен увидеть пользователь?
Ошибки сети случаются всегда. Хороший интерфейс объясняет, что произошло, и даёт следующий шаг.
-
Почему название блюда от сервера лучше вставлять через textContent, а не innerHTML?
Если в данных окажется тег script или подобное, innerHTML превратит его в часть страницы. textContent покажет как обычный текст.