Skip to content

GraphQL

GraphQL — это обычный POST с { query, variables }, поэтому особой поддержки не нужно: оберните один документ в эффект createRequestFx и передайте в createQuery / createMutation. Небольшая фабрика держит эндпоинт, заголовки, abort-сигнал и обработку ошибок в одном месте.

Переиспользуемая фабрика клиента

ts
import { createRequestFx, RequestError } from 'effector-refetch';

const ENDPOINT = 'https://countries.trevorblades.com/graphql';

interface GraphqlResponse<Data> {
  data?: Data;
  errors?: Array<{ message: string }>;
}

/** Один GraphQL-документ -> Abortable-эффект, принимающий свои переменные. */
export function graphql<Data, Vars = Record<string, never>>(document: string) {
  return createRequestFx<Vars, Data>(async (variables, { signal }) => {
    const res = await fetch(ENDPOINT, {
      method: 'POST',
      headers: { 'content-type': 'application/json' },
      body: JSON.stringify({ query: document, variables }),
      signal,
    });
    const json = (await res.json()) as GraphqlResponse<Data>;
    if (json.errors?.length) {
      throw new RequestError(json.errors[0].message, { status: res.status, data: json.errors });
    }
    return json.data as Data;
  });
}

Превращение GraphQL-errors в RequestError — ключевой момент: теперь retry, $error и инспектор обрабатывают ошибку уровня GraphQL ровно так же, как HTTP-ошибку.

Query

ts
import { createQuery } from 'effector-refetch';

const getCountriesFx = graphql<{ countries: Country[] }, { continent: string }>(`
  query Countries($continent: String!) {
    countries(filter: { continent: { eq: $continent } }) {
      code
      name
      emoji
    }
  }
`);

const countriesQuery = createQuery({ effect: getCountriesFx, cache: { staleAfter: 60_000 } });

countriesQuery.start({ continent: 'EU' });

Mutation

Та же фабрика обслуживает и записи — просто передайте эффект в createMutation:

ts
import { createMutation } from 'effector-refetch';

const addReviewFx = graphql<{ addReview: { id: string } }, { code: string; stars: number }>(`
  mutation AddReview($code: ID!, $stars: Int!) {
    addReview(code: $code, stars: $stars) {
      id
    }
  }
`);

const addReviewMutation = createMutation({ effect: addReviewFx, retry: 1 });

addReviewMutation.start({ code: 'EU', stars: 5 });

Поскольку переменные и есть параметры эффекта, connectQuery и combineQueries композируют GraphQL-операции так же, как REST.

Рабочий пример: examples/graphql.ts.

Под лицензией MIT