HTTP клиенты и fetch API

В веб-разработке часто возникает необходимость взаимодействовать с внешними сервисами и API. Для этого применяются HTTP-запросы, которые могут быть сделаны через различные механизмы. В Svelte, как и в других JavaScript-фреймворках, доступ к внешним данным осуществляется с использованием стандартных методов, таких как fetch. Важно понимать, как правильно работать с этими запросами, обрабатывать ответы и ошибки, а также как интегрировать такие операции в реактивные компоненты.

Что такое fetch API?

fetch — это стандартный JavaScript API для выполнения HTTP-запросов. Он предоставляет простой и мощный способ работы с асинхронными запросами. В отличие от старого объекта XMLHttpRequest, fetch возвращает промис, который решается с ответом от сервера или ошибкой, если запрос не удастся.

Пример базового использования:

fetch('https://api.example.com/data')
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.error('Ошибка:', error));

Метод fetch принимает URL в качестве обязательного аргумента и возвращает промис. Ответ от сервера можно обработать с помощью метода .then(), а ошибки можно перехватывать через .catch().

Асинхронные запросы в Svelte

В Svelte асинхронные запросы выполняются на тех же принципах, что и в чистом JavaScript. Однако интеграция с реактивными компонентами требует дополнительных шагов для правильного отображения данных.

Для выполнения асинхронных операций в компонентах Svelte используется специальный блок onMount, который позволяет выполнить код при монтировании компонента. Это полезно, когда необходимо загрузить данные при первом рендере компонента.

Пример запроса с использованием fetch и onMount:

<script>
  import { onMount } from 'svelte';

  let data = null;
  let loading = true;
  let error = null;

  onMount(async () => {
    try {
      const response = await fetch('https://api.example.com/data');
      if (!response.ok) {
        throw new Error('Сервер вернул ошибку');
      }
      data = await response.json();
    } catch (err) {
      error = err.message;
    } finally {
      loading = false;
    }
  });
</script>

{#if loading}
  <p>Загрузка...</p>
{:else if error}
  <p>Ошибка: {error}</p>
{:else}
  <ul>
    {#each data as item}
      <li>{item.name}</li>
    {/each}
  </ul>
{/if}

Здесь в onMount выполняется асинхронная функция, которая делает запрос к API и обрабатывает ответ. Пока данные загружаются, отображается сообщение о загрузке. Если запрос завершился с ошибкой, показывается соответствующее сообщение. Когда данные успешно получены, они выводятся на экран.

Обработка ошибок

Одна из важнейших задач при работе с HTTP-запросами — это правильная обработка ошибок. Метод fetch не отклоняет промис в случае ошибок HTTP, таких как 404 или 500. Он разрешает промис, даже если сервер вернул ошибку, поэтому для проверки успешности запроса необходимо использовать свойство response.ok, которое будет равно true, если код состояния HTTP находится в диапазоне 200-299.

Пример обработки ошибок:

fetch('https://api.example.com/data')
  .then(response => {
    if (!response.ok) {
      throw new Error('Ошибка при запросе');
    }
    return response.json();
  })
  .then(data => console.log(data))
  .catch(error => console.error('Ошибка:', error));

При использовании async/await можно легко обрабатывать ошибки с помощью try/catch:

try {
  const response = await fetch('https://api.example.com/data');
  if (!response.ok) {
    throw new Error('Ошибка при запросе');
  }
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error('Ошибка:', error);
}

Загрузка данных с параметрами

При отправке запросов на сервер часто бывает необходимо передавать параметры, такие как параметры URL или данные в теле запроса (для POST-запросов).

Пример использования параметров в URL:

const queryParams = new URLSearchParams({
  search: 'svelte',
  page: 1,
});

const url = `https://api.example.com/data?${queryParams.toString()}`;

fetch(url)
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.error('Ошибка:', error));

Пример отправки данных через POST-запрос:

const requestData = {
  name: 'John',
  age: 30,
};

fetch('https://api.example.com/submit', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify(requestData),
})
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.error('Ошибка:', error));

Заголовки и авторизация

Для многих API необходимо передавать дополнительные заголовки, такие как авторизационные токены или другие данные. В fetch можно легко добавлять заголовки в объект конфигурации.

Пример добавления авторизационного заголовка:

const token = 'your-auth-token';

fetch('https://api.example.com/data', {
  headers: {
    'Authorization': `Bearer ${token}`,
  },
})
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.error('Ошибка:', error));

Работа с серверными запросами в Svelte

В Svelte также предусмотрены возможности для взаимодействия с сервером с помощью серверных запросов. Хотя клиентский код, как правило, обрабатывает запросы через fetch, серверная логика может быть организована через серверные компоненты или API-роуты, которые можно использовать совместно с SvelteKit.

В серверной части можно использовать серверный API (например, через @sveltejs/kit) для обработки запросов, в то время как клиентская сторона будет использовать результаты этих запросов для обновления состояния.

Пример серверного API в SvelteKit:

// src/routes/api/data.js
export async function get() {
  const response = await fetch('https://external-api.com/data');
  const data = await response.json();

  return {
    status: 200,
    body: data,
  };
}

Здесь серверный маршрут обрабатывает GET-запрос, получает данные из внешнего API и возвращает их клиенту. Клиентский компонент может затем использовать данные, полученные через fetch, чтобы обновить интерфейс.

Кэширование запросов

При частом обращении к одному и тому же API полезно кэшировать результаты для повышения производительности и снижения нагрузки на сервер. Кэширование можно реализовать как на уровне браузера, так и через собственные механизмы, такие как сервис-воркеры.

Пример простого кэширования с использованием браузерного API:

let cachedData = null;

async function getData() {
  if (cachedData) {
    return cachedData;
  }

  const response = await fetch('https://api.example.com/data');
  const data = await response.json();
  cachedData = data;
  return data;
}

Такой подход предотвращает излишние запросы и улучшает скорость загрузки данных.

Выводы

Работа с HTTP-запросами в Svelte не сильно отличается от обычного JavaScript. Главное — правильно использовать асинхронные операции, обрабатывать возможные ошибки и интегрировать запросы в реактивную модель компонента. Важно помнить о безопасности, особенно при работе с авторизационными токенами и конфиденциальными данными.