Общее понятие JavaScript API в веб-разработке
Основы работы с JavaScript API
JavaScript API обеспечивает взаимодействие веб-приложений с серверными ресурсами. Современный стандарт fetch с async/await является наиболее эффективным и удобным решением для большинства задач.
Как выполнить GET запрос и обработать JSON ответ?
async function fetchData(url) {
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
return data;
} catch (error) {
console.error('Ошибка запроса:', error);
throw error;
}
}
fetchData('https://api.example.com/users')
.then(users => console.log(users))
.catch(err => console.error(err));Js api (javascript api (общее))
Пояснение: fetch возвращает объект Response. Свойство ok проверяет успешность HTTP статуса (200-299). Метод json() парсит тело ответа как JSON. Ошибки сети (нет соединения) перехватываются в блоке catch.
Типичные ошибки и их решение:
- Необработанная ошибка сети: всегда добавлять try/catch или .catch()
- Неверный статус: проверять response.ok, иначе ответ может быть JSON с ошибкой, который не распарсится
- Проблемы CORS: если сервер не разрешает кросс-доменные запросы, браузер блокирует ответ. Решение: настроить сервер или использовать прокси
Как выполнить асинхронный запрос без использования fetch? (XMLHttpRequest)
function loadData(url) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.onload = function() {
if (xhr.status >= 200 && xhr.status < 300) {
resolve(JSON.parse(xhr.responseText));
} else {
reject(new Error(`HTTP error: ${xhr.status}`));
}
};
xhr.onerror = function() {
reject(new Error('Network error'));
};
xhr.send();
});
}
loadData('https://api.example.com/users')
.then(data => console.log(data))
.catch(err => console.error(err));Text javascript src https apis (apis javascript)
Пояснение: XMLHttpRequest - классический способ, требует обёртки в Promise для удобства. onload срабатывает при получении ответа, onerror - при сетевой ошибке.
Проблемы: более громоздкий код, сложность с обработкой прогресса, отсутствие поддержки промисов из коробки.
Как обработать POST запрос с JSON телом?
async function postData(url, data) {
try {
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});
if (!response.ok) {
const errorText = await response.text();
throw new Error(`Server error: ${response.status} - ${errorText}`);
}
return await response.json();
} catch (error) {
console.error('POST request failed:', error);
throw error;
}
}
postData('https://api.example.com/users', { name: 'Иван', age: 30 })
.then(result => console.log(result));Важно установить заголовок Content-Type: application/json, иначе сервер может не распарсить тело. При ошибках сервера (4xx/5xx) стоит прочитать тело ответа, так как в нём может быть детальное сообщение.
Распространённая ошибка: забыть преобразовать объект в JSON строку (JSON.stringify) или не указать метод.
Как использовать стороннюю библиотеку Axios для упрощения запросов?
import axios from 'axios';
async function getUsers() {
try {
const response = await axios.get('https://api.example.com/users');
return response.data; // axios автоматически парсит JSON
} catch (error) {
if (error.response) {
console.error('Server responded with status', error.response.status);
} else if (error.request) {
console.error('No response received');
} else {
console.error('Request setup error', error.message);
}
throw error;
}
}Axios предоставляет удобные методы (get, post), автоматически преобразует ответ в JSON, обрабатывает таймауты, поддержка отмены запросов и перехватчиков (interceptors).
Недостатки: дополнительная зависимость, увеличение размера бандла. Для простых проектов fetch может быть достаточным.
Как выполнить GraphQL запрос через fetch?
async function graphqlQuery(url, query, variables = {}) {
const response = await fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ query, variables })
});
const result = await response.json();
if (result.errors) {
throw new Error('GraphQL Error: ' + JSON.stringify(result.errors));
}
return result.data;
}
graphqlQuery('https://api.example.com/graphql', `
query {
users {
id
name
}
}
`).then(data => console.log(data));GraphQL всегда использует POST, даже для запросов (хотя теоретически можно и GET). Ответ содержит поля data и errors.
Как работать с WebSocket API для реального времени?
const socket = new WebSocket('wss://api.example.com/ws');
socket.addEventListener('open', (event) => {
console.log('Соединение открыто');
socket.send(JSON.stringify({ type: 'subscribe', channel: 'updates' }));
});
socket.addEventListener('message', (event) => {
const data = JSON.parse(event.data);
console.log('Получено сообщение:', data);
});
socket.addEventListener('error', (event) => {
console.error('Ошибка WebSocket:', event);
});
socket.addEventListener('close', (event) => {
console.log('Соединение закрыто', event.code, event.reason);
});WebSocket устанавливает постоянное двустороннее соединение. Данные передаются в виде строк или бинарных данных. Сервер может отправлять сообщения в любой момент.
Типичные проблемы: потеря соединения (нужна логика переподключения), обработка разных типов сообщений, корректное закрытие сокета.
Каждый из вариантов имеет свои случаи использования: fetch - для большинства REST запросов, XMLHttpRequest - при работе с устаревшими браузерами или отслеживанием прогресса загрузки, Axios - для сложной конфигурации, GraphQL - для гибких запросов к одному endpoint, WebSocket - для чатов, игр, уведомлений.
Расширенные примеры работы с JavaScript API
Параллельные запросы с Promise.all
async function fetchMultipleUsers(userIds) {
const urls = userIds.map(id => `https://api.example.com/users/${id}`);
const promises = urls.map(url => fetch(url).then(res => res.json()));
const users = await Promise.all(promises);
return users;
}
fetchMultipleUsers([1, 2, 3]).then(users => console.log(users));
// Результат:
// [
// { id: 1, name: 'Анна' },
// { id: 2, name: 'Борис' },
// { id: 3, name: 'Виктор' }
// ][ { id: 1, name: 'Анна' }, { id: 2, name: 'Борис' }, { id: 3, name: 'Виктор' } ]
Если один из запросов падает, весь Promise.all отклоняется. Для устойчивости можно использовать Promise.allSettled.
Отмена запроса с AbortController
const controller = new AbortController();
const signal = controller.signal;
fetch('https://api.example.com/long-operation', { signal })
.then(response => response.json())
.catch(err => {
if (err.name === 'AbortError') {
console.log('Запрос отменён пользователем');
} else {
console.error('Ошибка:', err);
}
});
// Через 2 секунды отменяем запрос
setTimeout(() => controller.abort(), 2000);Полезно для поисковых полей с автодополнением (debounce), чтобы отменять устаревшие запросы.
Загрузка файла с прогрессом через fetch (используя ReadableStream)
async function uploadFile(url, file) {
const response = await fetch(url, {
method: 'POST',
body: file // FormData или Blob
});
// Для отслеживания прогресса загрузки на клиенте fetch не предоставляет встроенных средств,
// но можно использовать XMLHttpRequest или измерять размер отправленного чанка (сложно).
// Альтернатива: использовать библиотеку (например, axios с onUploadProgress).
return response.json();
}// Пример с XMLHttpRequest (отслеживание прогресса)
function uploadFileWithProgress(url, file, onProgress) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open('POST', url);
xhr.upload.addEventListener('progress', (e) => {
if (e.lengthComputable) {
const percent = Math.round((e.loaded / e.total) * 100);
onProgress(percent);
}
});
xhr.onload = () => {
if (xhr.status >= 200 && xhr.status < 300) {
resolve(JSON.parse(xhr.responseText));
} else {
reject(new Error('Upload failed'));
}
};
xhr.onerror = () => reject(new Error('Network error'));
xhr.send(file);
});
}
uploadFileWithProgress('/upload', file, (p) => console.log(`${p}%`));Обработка ошибок разных типов
async function safeFetch(url) {
try {
const response = await fetch(url);
// Проверка статуса
if (!response.ok) {
// Попытка извлечь детали ошибки из тела
let errorBody;
try {
errorBody = await response.json();
} catch {
errorBody = await response.text();
}
throw new Error(`HTTP ${response.status}: ${JSON.stringify(errorBody)}`);
}
return await response.json();
} catch (error) {
if (error instanceof TypeError && error.message.includes('fetch')) {
// Ошибка сети, CORS, неверный URL
console.error('Сетевая ошибка или CORS:', error);
}
throw error;
}
}Такой подход позволяет единообразно обрабатывать ошибки как на стороне сети, так и на стороне сервера.
Работа с куками и авторизацией
fetch('https://api.example.com/protected', {
method: 'GET',
credentials: 'include', // отправка кук (для same-origin и cross-origin с CORS)
headers: {
'Authorization': 'Bearer ' + getToken()
}
});Параметр credentials: 'include' обязателен, если сервер ожидает куки или сессию. Для кросс-доменов сервер должен установить заголовок Access-Control-Allow-Credentials: true.
Полиморфный запрос: обработка разных типов ответов
async function fetchWithType(url) {
const response = await fetch(url);
const contentType = response.headers.get('content-type');
if (contentType && contentType.includes('application/json')) {
return await response.json();
} else if (contentType && contentType.includes('text/')) {
return await response.text();
} else if (contentType && contentType.includes('image/')) {
// Для изображений можно получить blob и создать URL
const blob = await response.blob();
return URL.createObjectURL(blob);
} else if (contentType && contentType.includes('application/octet-stream')) {
const arrayBuffer = await response.arrayBuffer();
return arrayBuffer;
} else {
return await response.text();
}
}Применяется при работе с API, которые могут возвращать разные форматы (например, JSON при успехе и HTML при ошибке).
Повторная попытка при временных ошибках (retry)
async function fetchWithRetry(url, options = {}, retries = 3, delay = 1000) {
for (let attempt = 0; attempt <= retries; attempt++) {
try {
const response = await fetch(url, options);
if (!response.ok && response.status >= 500) {
// Серверная ошибка, стоит повторить
throw new Error(`Server error ${response.status}`);
}
return await response.json();
} catch (error) {
if (attempt === retries) throw error;
console.warn(`Попытка ${attempt + 1} не удалась, повтор через ${delay}ms`);
await new Promise(resolve => setTimeout(resolve, delay));
delay *= 2; // экспоненциальная задержка
}
}
}Полезно для API с временной недоступностью. Не применять к идемпотентным запросам (GET) без осторожности.