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
Комментарии