Аргументы, переменные и алиасы

Аргументы делают поля параметризуемыми, переменные выносят значения из текста запроса, а алиасы позволяют запросить одно поле несколько раз с разными аргументами.

Запрос без аргументов — как поиск без строки поиска. Аргументы превращают статичную выборку в гибкий инструмент.

Любое поле может принимать аргументы — именованные параметры в скобках. Через них клиент управляет тем, что вернёт резолвер: какого пользователя взять, сколько постов отдать, как отсортировать, как отфильтровать. Важно: аргументы есть не только у корневых полей, но и у любых вложенных. В одном запросе можно одновременно сказать «дай пользователя с id 42» и тут же «а его постов отдай только первые три, отсортированные по дате» — каждый уровень дерева управляется своими аргументами независимо. Это и делает GraphQL по-настоящему гибким: форма запроса задаётся выбором полей, а наполнение каждого уровня — его аргументами.

query {
  user(id: "42") {
    posts(first: 3, orderBy: CREATED_AT) {
      title
    }
  }
}

Переменные

Зашивать значения прямо в текст запроса — плохо: запрос становится одноразовым и его нельзя закэшировать. Правильно — объявить переменные и передать их значения отдельно:

query GetPosts($userId: ID!, $count: Int = 3) {
  user(id: $userId) {
    posts(first: $count) {
      title
    }
  }
}

А значения уходят отдельным JSON-блоком (variables):

{
  "userId": "42",
  "count": 5
}

Обрати внимание на $count: Int = 3 — это значение по умолчанию: если клиент не передаст count, подставится 3. Переменные типизированы, и сервер проверит их по схеме до выполнения.

Алиасы

Что если нужно запросить одно и то же поле дважды, но с разными аргументами? Без алиасов ключи в ответе совпадут и перезатрут друг друга. Алиас переименовывает поле в ответе:

query {
  active: users(status: ACTIVE) { name }
  banned: users(status: BANNED) { name }
}

В ответе появятся два разных ключа — active и banned — хотя резолвилось одно и то же поле users.

Как работает под капотом

Перед выполнением сервер подставляет значения переменных в дерево запроса и проверяет их типы по объявлению ($count: Int — значит должно прийти число). Дальше аргументы попадают вторым параметром в резолвер поля. Смоделируем резолвер с аргументами фильтрации и пагинации:

const posts = [
  { title: "A", status: "ACTIVE" },
  { title: "B", status: "BANNED" },
  { title: "C", status: "ACTIVE" },
  { title: "D", status: "ACTIVE" }
];

// резолвер поля: (parent, args)
function resolvePosts(_parent, args) {
  let res = posts;
  if (args.status) res = res.filter(p => p.status === args.status);
  if (args.first != null) res = res.slice(0, args.first);
  return res.map(p => p.title);
}

console.log(resolvePosts(null, { status: "ACTIVE", first: 2 })); // ["A","C"]
console.log(resolvePosts(null, { status: "BANNED" }));           // ["B"]

Попробуй сам ▶ — поменяй first и status в вызовах. Ровно так аргументы запроса управляют выборкой на сервере.

Частые ошибки

  • Хардкодить значения в запрос. Конкатенация значений в текст запроса ломает кэш и открывает дорогу инъекциям. Всегда используй переменные.
  • Забыть алиас при повторе поля. Два users(...) без алиасов конфликтуют по ключу — нужен active: и banned:.
  • Неверный тип переменной. Объявил $count: Int, а прислал строку — сервер отклонит запрос ещё на валидации.

Best practices

  • Всё, что меняется от запроса к запросу, выноси в типизированные переменные — это безопасно, кэшируемо и читаемо.
  • Задавай разумные значения по умолчанию для пагинации (first: Int = 20), чтобы клиент случайно не запросил всё разом.
  • Используй алиасы, когда строишь дашборды и сравнения: один запрос — несколько срезов одного и того же поля.

Итоги

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

Проверьте себя
1. Зачем выносить значения в переменные вместо вставки в текст запроса?
AТак быстрее печатать
BЗапрос становится переиспользуемым, кэшируемым и типобезопасным
CИначе сервер не примет запрос
DЧтобы скрыть поля
2. Что делает алиас в запросе?
AМеняет тип поля
BПереименовывает поле в ответе, позволяя запросить его несколько раз с разными аргументами
CДелает поле обязательным
DСоздаёт новую переменную