GraphQL — это язык запросов для среды выполнения на стороне сервера и API для выполнения запросов с использованием системы типов для наших данных.

Рассмотрим более сложные операции GraphQL, в том числе передачу переменных, директив, мутаций и др.

Переменные

Аргументы для запросов в большинстве приложений должны быть динамическими. Передавать динамические аргументы непосредственно в строку запроса было бы не лучшим решением.

К счастью, GraphQL позволяет передавать переменные в запрос операций.

Например, можно написать:

query PersonName($id: Int) {
  person(id: $id) {
    name
  }
}

и передать тем самым переменную $id в запрос person.

Затем можно передать переменные через объект, чтобы сделать запрос:

{
  "id": 1000
}

В качестве ответа получаем подобное:

{
  "data": {
    "person": {
      "name": "Jane"
    }
  }
}

Определения переменных

Определения переменных начинаются с префикса $ \, затем ставится имя переменной, и потом идёт тип переменной.

В приведённом нами примере имя переменной — $id, а тип переменной — Int.

Все объявленные переменные должны быть скалярного, перечисляемого или другого типа входного объекта.

Чтобы передать в поле сложный объект, необходимо знать тип входных данных, соответствующий ему на сервере.

Переменные по умолчанию

Для переменных можно задавать стандартные значения:

query PersonName($id: Int = 1) {
  person(id: $id) {
    name
  }
}

Здесь мы добавили = 1 после $id: Int, установив для переменной $id стандартное значение, равное 1.

Директивы

Для динамического изменения структуры и формы запросов, использующих переменные, можно задействовать директивы.

Например, чтобы сделать наш запрос динамическим, включим в него директивы:

query Person($id: Int, $withFriends: Boolean!) {
  person(id: $id) {
    name
    friends @include(if: $withFriends) {
      name
    }
  }
}

В этом коде директива @include(if: $withFriends) включает friends при условии, если $withFriends будет true.

Поэтому при выполнении запроса со следующими переменными:

{
  "id": 1000,
  "withFriends": false
}

В качестве ответа мы получим подобное:

{
  "data": {
    "person": {
      "name": "Jane"
    }
  }
}

Директива прикрепляется к полю или включению фрагмента и может влиять на выполнение запроса желаемым для сервера способом.

Базовая спецификация GraphQL имеет две директивы, возможность использования которых должна быть в любой совместимой с ней серверной реализации GraphQL:

  • @include(if: Boolean) — включаем это поле, только если аргумент будет true;
  • @skip(if: Boolean) — пропускаем это поле, если аргумент будет true.

Такой подход помогает при работе со строками, когда приходится добавлять и удалять поля в запросе.

Мутации

Для отправки запросов на изменение данных на сервере можно использовать мутации.

Они отличаются от запросов тем, что начинаются с ключевого слова mutation.

Например, можно определить мутацию следующим образом:

mutation CreatePerson($firstName: String, $lastName: String) {
  createPerson(firstName: $firstName, lastName: $lastName) {
    firstName
    lastName
  }
}

Тогда при выполнении такого запроса:

{
  "firstName": "Joe",
  "lastName": "Smith"
}

можно ожидать такой ответ:

{
  "data": {
    "createPerson": {
      "firstName": "Joe",
      "lastName": "Smith"
    }
  }
}

Здесь мы возвращаем те же поля firstName и lastName, что указывали в запросе.

В мутации, как и в запросе, несколько полей. Поля мутации выполняются последовательно, то есть при отправке в одном запросе двух мутаций createPerson первая завершится прежде, чем начнётся вторая.

Встраиваемые фрагменты

С помощью запросов GraphQL можно определять типы интерфейсов и объединений. С этой целью используем встраиваемые фрагменты для доступа к данным в базовом конкретном типе.

Например, напишем следующий запрос:

query Thing($id: Int!) {
  person(id: $id) {
    name
    ... on Person{
      gender
    }
    ... on Robot{
      memory
    }
  }
}

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

Эти фрагменты также могут быть встраиваемыми благодаря наличию типа.

Метаполя

Наконец, можно запросить поле __typename, чтобы получить тип данных, возвращаемых в ответе.

Например, при выполнении следующего запроса:

{
  search(text: "an") {
    __typename
    ... on Human {
      name
    }
    ... on Robot {
      name
    }
  }
}

… от сервера может поступить такой ответ:

{
  "data": {
    "search": [
      {
        "__typename": "Human",
        "name": "Hans"
      },
      {
        "__typename": "Robot",
        "name": "Jane"
      }
    ]
  }
}

Заключение

Мы можем определять мутации для выполнения запросов на изменение данных.

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

Наконец, с помощью свойства __typename мы можем использовать встраиваемые фрагменты для типов объединений и получать тип данных, возвращаемых в ответе.

Читайте также:


Перевод статьи John Au-Yeung: Introduction to GraphQL — Variables and Complex Operations