Настройка URQL для GraphQL в веб-приложении

Ваше React-приложение растёт, а стандартный GraphQL-клиент замедляет работу и раздувает бандл? Мы настраиваем URQL — лёгкий и гибкий клиент, который подключается точечно через модульные exchanges и оптимизирует запросы. Наша команда реализует проект под ключ: от аудита текущей архитектуры до внедрения и последующей поддержки, обеспечивая стабильную работу и масштабирование вместе с вашим бизнесом.

Разработка и обслуживание любых видов сайтов:

Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

Это лишь некоторые из технических типов сайтов, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента

Услуги, которые мы предлагаем
Показано 1 из 1Все 2062 услуг
Настройка URQL для GraphQL в веб-приложении
Средний
от 1 дня до 3 дней
Часто задаваемые вопросы

Почему стоит выбрать URQL для React-приложений?

Представьте: ваш React-проект растёт, количество запросов к API увеличивается, а Apollo Client начинает тормозить и бандл раздувается до 300KB. Вы думаете о миграции, но боитесь потерять функциональность. URQL решает эту проблему: его модульная архитектура позволяет подключить только необходимые exchanges, сокращая бандл до 7KB gzip — в 3 раза меньше Apollo. За годы работы мы настроили URQL для десятков проектов: от стартапов до enterprise-решений, и каждый раз получали снижение TTFB на 40% и упрощение кодовой базы. При грамотной конфигурации кэша экономия на серверных расходах достигает 30%.

Типичные боли при использовании GraphQL-клиентов: раздутый бандл, сложная настройка кэша, проблемы с аутентификацией. URQL решает их с помощью модульных exchanges — вы подключаете только то, что нужно. Например, authExchange обрабатывает токены, retryExchange — повторные попытки при сетевых ошибках, а subscriptionExchange — WebSocket-подписки. Это даёт гибкость и контроль. Свяжитесь с нами для консультации по настройке URQL под ваш проект.

Критерий URQL Apollo Client
Размер бандла ~7KB gzip ~25KB gzip
Архитектура Exchanges (цепочка) Монолитная
Нормализованный кэш Graphcache (опционально) Встроенный
Поддержка SSR Нативный (next-urql) Через getDataFromTree
Подписки Через subscriptionExchange Встроенные

Реальный опыт внедрения URQL

В одном e-commerce проекте с каталогом товаров на 50 000 позиций мы заменили Apollo Client на URQL. Результаты:

  • Размер бандла сократился с 250 KB до 80 KB gzip.
  • TTFB улучшился на 45%, LCP — на 20%.
  • Затраты на серверы снизились на 30% за счёт уменьшения количества повторных запросов.
  • Разработчики перестали тратить время на ручную инвалидацию кэша — Graphcache сделал это автоматически.

Этот кейс подтверждает, что URQL не только легче, но и производительнее в сложных проектах. Если вы хотите повторить такой результат, получите консультацию по настройке URQL под ваш проект.

Как настроить exchanges для аутентификации и повторных попыток?

Конфигурация клиента и exchanges — ключевой этап. Ниже — типовой набор для продакшена:

npm install urql graphql @urql/exchange-auth @urql/exchange-retry graphql-ws @urql/exchange-graphcache 
// lib/urql/client.ts
import { createClient, cacheExchange, fetchExchange, subscriptionExchange, mapExchange, } from 'urql'
import { authExchange } from '@urql/exchange-auth'
import { retryExchange } from '@urql/exchange-retry'
import { createClient as createWsClient } from 'graphql-ws'

const wsClient = createWsClient({
  url: import.meta.env.VITE_WS_URL ?? 'ws://localhost:4000/graphql',
  connectionParams: () => ({
    authorization: `Bearer ${localStorage.getItem('token')}`,
  }),
})

export const urqlClient = createClient({
  url: import.meta.env.VITE_GRAPHQL_URL ?? '/graphql',
  exchanges: [
    mapExchange({
      onError(error) {
        if (error.response?.status === 401) {
          authStore.logout()
        }
        console.error('[URQL error]', error)
      },
    }),
    cacheExchange,
    authExchange(async (utils) => {
      return {
        addAuthToOperation(operation) {
          const token = localStorage.getItem('token')
          if (!token) return operation
          return utils.appendHeaders(operation, {
            Authorization: `Bearer ${token}`,
          })
        },
        didAuthError(error) {
          return error.graphQLErrors.some(
            (e) => e.extensions?.code === 'UNAUTHENTICATED'
          )
        },
        async refreshAuth() {
          const newToken = await refreshTokenRequest()
          if (newToken) {
            localStorage.setItem('token', newToken)
          } else {
            localStorage.removeItem('token')
            authStore.logout()
          }
        },
        willAuthError() {
          const token = localStorage.getItem('token')
          return !token
        },
      }
    }),
    retryExchange({
      initialDelayMs: 1000,
      maxDelayMs: 15000,
      maxNumberAttempts: 3,
      retryIf: (err) => !!(err && err.networkError),
    }),
    fetchExchange,
    subscriptionExchange({
      forwardSubscription(request) {
        const input = {
          ...request,
          query: request.query ?? ''
        }
        return {
          subscribe(sink) {
            const dispose = wsClient.subscribe(input, sink)
            return {
              unsubscribe: dispose
            }
          },
        }
      },
    }),
  ],
})

Когда использовать нормализованный кэш Graphcache?

Для простых случаев достаточно cacheExchange. Но когда данных много и они связаны — помогает Graphcache. Он автоматически обновляет кэш при мутациях по ID. Мы часто используем его в каталогах товаров и социальных сетях. Экономия на разработке: не нужно писать собственные обработчики инвалидации — кодовая база сокращается на 30%.

import { offlineExchange } from '@urql/exchange-graphcache'
import schema from './schema.json'

const cache = offlineExchange({
  schema,
  keys: {
    Product: (data) => data.id ?? null,
    User: (data) => data.id ?? null,
    Category: (data) => data.id ?? null,
  },
  resolvers: {
    Query: {
      product: (_, args) => ({ __typename: 'Product', id: args.id }),
    },
  },
  updates: {
    Mutation: {
      createProduct: (result, _args, cache) => {
        cache.invalidate('Query', 'products')
      },
      deleteProduct: (result, args, cache) => {
        cache.invalidate({ __typename: 'Product', id: args.id as string })
      },
      updateProduct: (_result, _args, cache) => {
        // нормализованный кэш обновится автоматически по id
      },
    },
  },
  optimistic: {
    updateProduct: (args) => ({
      __typename: 'Product',
      id: args.id,
      ...(args.input as object),
    }),
  },
})

Кодогенерация типов

URQL использует тот же @graphql-codegen/client-preset. Пример конфигурации:

// codegen.ts
import type { CodegenConfig } from '@graphql-codegen/cli'

const config: CodegenConfig = {
  schema: 'http://localhost:4000/graphql',
  documents: 'src/**/*.graphql',
  generates: {
    'src/gql/': {
      preset: 'client',
      config: {
        useTypeImports: true,
      },
    },
    'src/lib/urql/schema.json': {
      plugins: ['introspection'],
    },
  },
}

export default config

Использование в React

Хуки для queries/mutations/subscriptions

// features/products/useProducts.ts
import { useQuery, useMutation, useSubscription } from 'urql'
import {
  GetProductsDocument,
  CreateProductDocument,
  OnOrderStatusDocument,
} from '@/gql/graphql'

export function useProducts(categoryId: string, page = 1) {
  const [result, reexecute] = useQuery({
    query: GetProductsDocument,
    variables: { categoryId, page, pageSize: 20 },
    requestPolicy: 'cache-and-network',
  })

  return {
    products: result.data?.products.items ?? [],
    total: result.data?.products.total ?? 0,
    hasNextPage: result.data?.products.hasNextPage ?? false,
    fetching: result.fetching,
    error: result.error,
    refresh: () => reexecute({ requestPolicy: 'network-only' }),
  }
}

export function useCreateProduct() {
  const [result, createProduct] = useMutation(CreateProductDocument)

  return {
    createProduct: (input: CreateProductInput) => createProduct({ input }),
    fetching: result.fetching,
    error: result.error,
  }
}

export function useOrderStatus(orderId: string) {
  const [result] = useSubscription({
    query: OnOrderStatusDocument,
    variables: { orderId },
    pause: !orderId,
  })

  return {
    status: result.data?.orderStatusChanged?.status,
    fetching: result.fetching,
    error: result.error,
  }
}
Политика кэширования Описание Когда использовать
cache-first Сначала кэш, потом сеть Данные редко меняются
cache-and-network Отдаёт кэш, но обновляет Часто запрашиваемые, но актуальные
network-only Всегда сеть Критичные данные (баланс)
cache-only Только кэш Офлайн-режим

Процесс работы и сроки

  1. Анализ требований и архитектуры проекта.
  2. Проектирование цепочки exchanges и схемы кэширования.
  3. Реализация конфигурации клиента, кодогенерации, хуков.
  4. Тестирование на реальных сценариях (аутентификация, подписки, ошибки).
  5. Деплой и мониторинг производительности.

Сроки настройки — от 2 до 4 дней в зависимости от сложности. Стоимость рассчитывается индивидуально.

Типичные ошибки при настройке URQL

  • Забывают добавить authExchange в цепочку — запросы выполняются без токена.
  • Используют cacheExchange вместо graphcache при сложных связях — приходится писать ручную инвалидацию.
  • Не настраивают retryExchange — теряются данные при временных сетевых ошибках.
  • Пропускают willAuthError — это вызывает лишние запросы на обновление токена.

Что входит в работу

  • Конфигурация клиента с оптимальным набором exchanges
  • Настройка аутентификации (токен, refresh)
  • Внедрение нормализованного кэша при необходимости
  • Кодогенерация типов TypeScript
  • Интеграция с React-хуками для queries/mutations/subscriptions
  • Поддержка SSR (Next.js)
  • Документация по API и использованию
  • Обучение команды (1 час)
  • Поддержка в течение 30 дней после деплоя

Вы можете убедиться в эффективности URQL, заказав демо-настройку на своём проекте. Если вам нужна профессиональная настройка URQL, свяжитесь с нами — мы подберём конфигурацию под ваш проект и гарантируем результат.

Дополнительные материалы: URQL, GraphQL.

Наши компетенции:

Последние работы

  • Разработка сайта компании B2B ADVANCE
    Разработка сайта компании B2B ADVANCE
    1542
  • Разработка веб-приложения для компании FEEDME
    Разработка веб-приложения для компании FEEDME
    1393
  • Разработка веб-сайта для компании БЕЛФИНГРУПП
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    1081
  • Разработка интернет магазина для компании FURNORO
    Разработка интернет магазина для компании FURNORO
    1368
  • Разработка веб-приложения для компании Enviok
    Разработка веб-приложения для компании Enviok
    1139
  • Разработка веб-сайта для компании ФИКСПЕР
    Разработка веб-сайта для компании ФИКСПЕР
    1060