Работа с REST API и GraphQL

Hyperapp — это минималистичный фронтенд-фреймворк, основанный на концепции функционального подхода к управлению состоянием и виртуального DOM. Несмотря на компактность ядра, Hyperapp позволяет эффективно работать с внешними API, включая REST и GraphQL, через асинхронные эффекты (effects) и действия (actions).


Асинхронные эффекты и их роль

В Hyperapp эффект — это функция, которая выполняет побочные действия, такие как сетевые запросы. Эффекты не изменяют состояние напрямую, а получают состояние и вызывают действие, которое уже его обновляет. Основная структура эффекта:

const fetchEffect = (url, action) => (state, actions) => {
  fetch(url)
    .then(res => res.json())
    .then(data => actions[action](data))
    .catch(err => console.error(err));
};

В примере выше fetchEffect получает URL и имя действия, которое будет вызвано после получения данных.


Интеграция с REST API

Для работы с REST API часто используется комбинация эффектов и действий. Состояние (state) хранит данные, полученные с сервера, а действия обрабатывают успешные или ошибочные ответы.

Пример работы с REST API:

const state = {
  users: [],
  loading: false,
  error: null
};

const actions = {
  fetchUsers: () => (state, actions) => {
    actions.setLoading(true);
    fetchEffect('https://jsonplaceholder.typicode.com/users', 'setUsers')(state, actions);
  },
  setUsers: (users) => ({ users, loading: false }),
  setLoading: (loading) => ({ loading }),
  setError: (error) => ({ error, loading: false })
};

В этом примере:

  • fetchUsers запускает асинхронный эффект;
  • setUsers обновляет состояние после получения данных;
  • setLoading и setError управляют индикатором загрузки и обработкой ошибок.

Работа с GraphQL

GraphQL требует отправки запросов методом POST с JSON-телом запроса. В Hyperapp структура остается аналогичной REST: эффект делает запрос, действие обновляет состояние.

Пример запроса к GraphQL:

const graphqlEffect = (query, variables, action) => (state, actions) => {
  fetch('https://graphql.example.com', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ query, variables })
  })
    .then(res => res.json())
    .then(data => actions[action](data.data))
    .catch(err => console.error(err));
};

const state = {
  posts: [],
  loading: false
};

const actions = {
  fetchPosts: () => (state, actions) => {
    actions.setLoading(true);
    const query = `
      query {
        posts {
          id
          title
          content
        }
      }
    `;
    graphqlEffect(query, {}, 'setPosts')(state, actions);
  },
  setPosts: (posts) => ({ posts, loading: false }),
  setLoading: (loading) => ({ loading })
};

Особенности GraphQL-запросов:

  • query описывает, какие данные нужны;
  • variables позволяют передавать динамические параметры;
  • действие обновляет состояние только после успешного получения данных.

Обработка ошибок и индикаторов загрузки

Для поддержания отзывчивого интерфейса важно отслеживать процесс загрузки и ошибки:

const actions = {
  fetchData: () => (state, actions) => {
    actions.setLoading(true);
    fetchEffect('https://api.example.com/data', 'setData')(state, actions);
  },
  setData: (data) => ({ data, loading: false, error: null }),
  setError: (error) => ({ error, loading: false }),
  setLoading: (loading) => ({ loading })
};

Индикаторы загрузки можно связать с state.loading, а ошибки — с state.error. Это позволяет создавать динамическое отображение состояния запросов.


Комбинирование нескольких эффектов

В реальных приложениях часто нужно запускать несколько запросов одновременно. Hyperapp позволяет комбинировать эффекты через массивы действий:

const actions = {
  fetchAllData: () => [
    (state, actions) => fetchEffect('/users', 'setUsers')(state, actions),
    (state, actions) => fetchEffect('/posts', 'setPosts')(state, actions)
  ]
};

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


Оптимизация и кеширование

Для повышения производительности можно:

  • кешировать ответы API в state и использовать их повторно;
  • ограничивать количество сетевых запросов, например через debounce для ввода поисковых данных;
  • обрабатывать ошибки централизованно, чтобы не дублировать обработку в каждом эффекте.

Практические рекомендации

  • Все асинхронные операции следует оборачивать в эффекты, чтобы сохранить чистоту действий и предсказуемость состояния.
  • Использовать структурированные состояния (loading, error, data) для удобного управления интерфейсом.
  • При работе с GraphQL применять переменные вместо динамического подставления данных в строку запроса.
  • Централизованная обработка ошибок упрощает поддержку и масштабирование приложения.

Эти подходы позволяют эффективно интегрировать Hyperapp с любыми внешними API, сохраняя минималистичность фреймворка, но при этом реализуя современные стандарты асинхронной работы с данными.