Аргументы, переменные и алиасы
Аргументы делают поля параметризуемыми, переменные выносят значения из текста запроса, а алиасы позволяют запросить одно поле несколько раз с разными аргументами.
Запрос без аргументов — как поиск без строки поиска. Аргументы превращают статичную выборку в гибкий инструмент.
Любое поле может принимать аргументы — именованные параметры в скобках. Через них клиент управляет тем, что вернёт резолвер: какого пользователя взять, сколько постов отдать, как отсортировать, как отфильтровать. Важно: аргументы есть не только у корневых полей, но и у любых вложенных. В одном запросе можно одновременно сказать «дай пользователя с 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), чтобы клиент случайно не запросил всё разом. - Используй алиасы, когда строишь дашборды и сравнения: один запрос — несколько срезов одного и того же поля.
Итоги
Аргументы параметризуют поля (фильтр, сортировка, пагинация), переменные выносят значения из текста запроса и типизируются по схеме, а алиасы дают запросить одно поле несколько раз под разными ключами. Аргументы приходят в резолвер и управляют выборкой. Дальше — фрагменты и директивы для переиспользования и условной выборки.