В первом уроке мы отправили простой запрос: «дай мне пользователя и его имя». Настоящему приложению нужно больше. Пользователь вводит id в форму — как подставить его в запрос? Нужно загрузить сразу двух пользователей. Десять экранов запрашивают одни и те же поля — неужели копировать их десять раз? Для всего этого в запросах GraphQL есть инструменты: аргументы, переменные, алиасы, фрагменты и директивы. Представьте бланк заказа в кафе. Блюда в бланке — это поля, пометки вроде «без лука» — аргументы, а пустые клеточки, которые вы каждый раз заполняете по-новому, — переменные. Алиас позволяет заказать одно блюдо дважды, подписав «для Лейлы» и «для Мурада», а фрагмент — это «комбо-набор», который не нужно расписывать заново.

Анатомия запроса

Запрос GraphQL — это текст в особом формате. Вот полный запрос с именем GetUser; пока не вчитывайтесь в каждую деталь, мы разберём их по очереди:

graphql
query GetUser($id: ID!) {
  user(id: $id) {
    name
    email
  }
}

Из чего он состоит:

  1. Тип операции — query, mutation или subscription. Здесь это чтение данных.
  2. Имя операции — GetUser. Его придумываете вы. Сервер сработает и без имени, но с именем запрос проще найти в логах, инструментах отладки и отчётах об ошибках.
  3. Определение переменных — ($id: ID!). Заготовка под значение, которое придёт отдельно. Подробно — ниже.
  4. Поле с аргументом — user(id: $id): поле user из типа Query и его аргумент id.
  5. Набор полей (selection set) — всё, что внутри фигурных скобок { }: перечень того, что вы хотите получить.
Анатомия запроса GraphQL: тип операции, имя, переменные, поле с аргументом и набор полей
Анатомия запроса GraphQL: тип операции, имя, переменные, поле с аргументом и набор полей

Наборы полей вкладываются друг в друга сколько угодно раз — как рёбра графа из прошлого урока: user { posts { comments { text } } }. Правило одно: у поля, которое возвращает объект (user, posts), обязательно должен быть свой набор { … }, а у скаляра (name, email) — не должно. Запрос { user(id: "1") } без набора полей — ошибка: сервер ответит Field "user" of type "User" must have a selection of subfields. «Верни всё» в GraphQL не бывает, вы всегда перечисляете нужное.

Если у запроса нет ни имени, ни переменных, слово query можно опустить: { users { name } } — так мы писали в первом уроке.

Аргументы

Аргументы передают полю параметры, как аргументы функции. Они пишутся в круглых скобках после имени поля: user(id: "1"). В схеме из прошлого урока у user один обязательный аргумент id, а у posts — необязательный published. Запросим сразу два корневых поля:

graphql
{
  user(id: "1") {
    name
  }
  posts(published: true) {
    title
  }
}

Значения записываются почти как в JSON: строки — в двойных кавычках, числа, true, false и null — как есть, списки — [1, 2, 3]. Но есть два отличия: ключи объектов пишутся без кавычек, а значения enum — без кавычек вообще (orderBy: OLDEST). Аргументы бывают и у вложенных полей, не только у корневых.

Корневых полей в одном запросе может быть сколько угодно, и у каждого в ответе свой ключ: data.user и data.posts. Независимые поля сервер вправе выполнять параллельно.