0 added
0 removed
Original
2026-01-01
Modified
2026-02-26
1
<p><strong>Это руководство по GraphQL. Из него вы узнаете базовую теорию, а также научитесь писать простые запросы с помощью GraphQL.</strong></p>
1
<p><strong>Это руководство по GraphQL. Из него вы узнаете базовую теорию, а также научитесь писать простые запросы с помощью GraphQL.</strong></p>
2
<h2>Содержание</h2>
2
<h2>Содержание</h2>
3
<ul><li><a>Что такое GraphQL: теоретический ликбез</a></li>
3
<ul><li><a>Что такое GraphQL: теоретический ликбез</a></li>
4
<li><a>Query: запросы в GraphQL</a></li>
4
<li><a>Query: запросы в GraphQL</a></li>
5
<li><a>Mutation: мутации в GraphQL</a></li>
5
<li><a>Mutation: мутации в GraphQL</a></li>
6
<li><a>Subscription: подписки в GraphQL</a></li>
6
<li><a>Subscription: подписки в GraphQL</a></li>
7
<li><a>Как работать с сервером GraphQL</a></li>
7
<li><a>Как работать с сервером GraphQL</a></li>
8
<li><a>REST vs. GraphQL</a></li>
8
<li><a>REST vs. GraphQL</a></li>
9
<li><a>Заключение</a></li>
9
<li><a>Заключение</a></li>
10
</ul><h2>Что такое GraphQL: теоретический ликбез</h2>
10
</ul><h2>Что такое GraphQL: теоретический ликбез</h2>
11
<p>Прежде чем рассматривать GraphQL, давайте уделим внимание исторической базе. Что такое SQL - structured query language или язык структурированных запросов?</p>
11
<p>Прежде чем рассматривать GraphQL, давайте уделим внимание исторической базе. Что такое SQL - structured query language или язык структурированных запросов?</p>
12
<p>SQL - декларативный язык программирования, который применяется для создания, изменения и управления данными в базах данных. Этот язык поддерживает четыре базовых оператора запросов: SELECT, INSERT, UPDATE и DELETE. С помощью SQL мы можем запросить из базы данных (БД) именно то, что нам необходимо.</p>
12
<p>SQL - декларативный язык программирования, который применяется для создания, изменения и управления данными в базах данных. Этот язык поддерживает четыре базовых оператора запросов: SELECT, INSERT, UPDATE и DELETE. С помощью SQL мы можем запросить из базы данных (БД) именно то, что нам необходимо.</p>
13
<p>Например, когда необходимо "достать" из БД всех пользователей с именем Maria, это можно сделать с помощью запроса:</p>
13
<p>Например, когда необходимо "достать" из БД всех пользователей с именем Maria, это можно сделать с помощью запроса:</p>
14
<p>Решить эту задачу с помощью REST можно несколькими способами:</p>
14
<p>Решить эту задачу с помощью REST можно несколькими способами:</p>
15
<ol><li>Определить endpoint на сервере, который будет отдавать из базы данных пользователей с fname Maria.</li>
15
<ol><li>Определить endpoint на сервере, который будет отдавать из базы данных пользователей с fname Maria.</li>
16
<li>Определить общий endpoint для получения всех пользователей и фильтровать полученный список на стороне клиента.</li>
16
<li>Определить общий endpoint для получения всех пользователей и фильтровать полученный список на стороне клиента.</li>
17
</ol><p>При этом в каждом из вариантов есть свои минусы. Первый подход нельзя масштабировать, так как нет возможности создать endpoint для каждого пользователя. Если мы используем второй подход, повышается нагрузка на сеть, а также появляется необходимость в постобработке на стороне клиента.</p>
17
</ol><p>При этом в каждом из вариантов есть свои минусы. Первый подход нельзя масштабировать, так как нет возможности создать endpoint для каждого пользователя. Если мы используем второй подход, повышается нагрузка на сеть, а также появляется необходимость в постобработке на стороне клиента.</p>
18
<p>А теперь представьте инструмент, который объединяет возможности SQL и REST на стороне клиента. Вы уже догадались, что он называется GraphQL. Этот инструмент берёт идеи, разработанные для манипуляции данными в БД, и использует их в вебе. Поэтому с помощью одного запроса GraphQL можно получить сразу все необходимые данные.</p>
18
<p>А теперь представьте инструмент, который объединяет возможности SQL и REST на стороне клиента. Вы уже догадались, что он называется GraphQL. Этот инструмент берёт идеи, разработанные для манипуляции данными в БД, и использует их в вебе. Поэтому с помощью одного запроса GraphQL можно получить сразу все необходимые данные.</p>
19
<p>Ниже представлена информация, необходимая для начала работы с GraphQL.</p>
19
<p>Ниже представлена информация, необходимая для начала работы с GraphQL.</p>
20
<h2>Query: запросы в GraphQL</h2>
20
<h2>Query: запросы в GraphQL</h2>
21
<p>С помощью запросов GraphQL получает необходимые данные с сервера. Тип запроса Query в GraphQL - аналог GET в REST. Запросы - строки, которые отправляются в теле HTTP POST-запроса.</p>
21
<p>С помощью запросов GraphQL получает необходимые данные с сервера. Тип запроса Query в GraphQL - аналог GET в REST. Запросы - строки, которые отправляются в теле HTTP POST-запроса.</p>
22
<p><em>Примечание - Обратите внимание, все типы запросов в GraphQL отправляются через POST.</em></p>
22
<p><em>Примечание - Обратите внимание, все типы запросов в GraphQL отправляются через POST.</em></p>
23
<p>Query описывает данные, которые необходимо получить с сервера. Например, с помощью кода ниже можно получить fname и age всех пользователей в базе данных.</p>
23
<p>Query описывает данные, которые необходимо получить с сервера. Например, с помощью кода ниже можно получить fname и age всех пользователей в базе данных.</p>
24
<p>В ответ на этот запрос сервер присылает данные в формате JSON. Структура ответа соответствует структуре запроса.</p>
24
<p>В ответ на этот запрос сервер присылает данные в формате JSON. Структура ответа соответствует структуре запроса.</p>
25
<p>Успешные операции возвращают JSON с ключом "data" и с ключом "error", а неуспешные возвращают JSON с ключом и сообщением об ошибке. Благодаря этому удобно обрабатывать ошибки на стороне клиента.</p>
25
<p>Успешные операции возвращают JSON с ключом "data" и с ключом "error", а неуспешные возвращают JSON с ключом и сообщением об ошибке. Благодаря этому удобно обрабатывать ошибки на стороне клиента.</p>
26
<h2>Mutation: мутации в GraphQL</h2>
26
<h2>Mutation: мутации в GraphQL</h2>
27
<p>Mutation - ещё один root types. С его помощью можно добавлять данные в БД. Mutation - аналог POST и PUT в REST. Ниже пример кода.</p>
27
<p>Mutation - ещё один root types. С его помощью можно добавлять данные в БД. Mutation - аналог POST и PUT в REST. Ниже пример кода.</p>
28
<p>Здесь создаётся мутация createUser, которая добавляет в БД пользователя с fname Richie и age 22. В ответ на этот запрос сервер присылает JSON с id записи. Ответ выглядит так:</p>
28
<p>Здесь создаётся мутация createUser, которая добавляет в БД пользователя с fname Richie и age 22. В ответ на этот запрос сервер присылает JSON с id записи. Ответ выглядит так:</p>
29
<h2>Subscription: подписки в GraphQL</h2>
29
<h2>Subscription: подписки в GraphQL</h2>
30
<p>Subscription - третий тип операций в GraphQL. С его помощью клиент слушает изменения в БД в режиме реального времени. Под капотом подписки используют вебсокеты. Пример кода:</p>
30
<p>Subscription - третий тип операций в GraphQL. С его помощью клиент слушает изменения в БД в режиме реального времени. Под капотом подписки используют вебсокеты. Пример кода:</p>
31
<p>С помощью этого запроса можно получать список пользователей с именами и количеством лайков каждый раз, когда оно меняется.</p>
31
<p>С помощью этого запроса можно получать список пользователей с именами и количеством лайков каждый раз, когда оно меняется.</p>
32
<p>Например, когда пользователь с fname Richie получает лайк, ответ будет таким:</p>
32
<p>Например, когда пользователь с fname Richie получает лайк, ответ будет таким:</p>
33
<p>Подобный запрос можно использовать для обновления количества лайков в режиме реального времени в соответствующем интерфейсе, например, в форме с результатами голосования на сайте.</p>
33
<p>Подобный запрос можно использовать для обновления количества лайков в режиме реального времени в соответствующем интерфейсе, например, в форме с результатами голосования на сайте.</p>
34
<p>Выше представлены три основных типа запросов в GraphQL. Несмотря на поверхностное знакомство, вы получили достаточно знаний, чтобы начать работать со схемой GraphQL.</p>
34
<p>Выше представлены три основных типа запросов в GraphQL. Несмотря на поверхностное знакомство, вы получили достаточно знаний, чтобы начать работать со схемой GraphQL.</p>
35
<h2>Как работать с сервером GraphQL</h2>
35
<h2>Как работать с сервером GraphQL</h2>
36
<p>Рассмотрим ответ на этот вопрос на конкретном примере.</p>
36
<p>Рассмотрим ответ на этот вопрос на конкретном примере.</p>
37
<p>Цель: настроить сервер GraphQL, который отвечает на три типа запросов к БД NoSQL, в которой есть список пользователей с такой структурой:</p>
37
<p>Цель: настроить сервер GraphQL, который отвечает на три типа запросов к БД NoSQL, в которой есть список пользователей с такой структурой:</p>
38
<p>Также в базе данных есть списки постов, которые опубликовали пользователи.</p>
38
<p>Также в базе данных есть списки постов, которые опубликовали пользователи.</p>
39
<p>Для дальнейшей работы понадобится<a>сервер Apollo</a>. Это сервер GraphQL с открытым исходным кодом.</p>
39
<p>Для дальнейшей работы понадобится<a>сервер Apollo</a>. Это сервер GraphQL с открытым исходным кодом.</p>
40
<p>Настройте проект и установите зависимости:</p>
40
<p>Настройте проект и установите зависимости:</p>
41
<p>Вы создали пустой проект. Теперь установите GraphQL, Apollo и nodemon для отслеживания изменений в файлах.</p>
41
<p>Вы создали пустой проект. Теперь установите GraphQL, Apollo и nodemon для отслеживания изменений в файлах.</p>
42
<p>Чтобы nodemon работал, добавьте в package.json запись:</p>
42
<p>Чтобы nodemon работал, добавьте в package.json запись:</p>
43
<p>"scripts": "start": "nodemon -e js, json, graphql"</p>
43
<p>"scripts": "start": "nodemon -e js, json, graphql"</p>
44
<h3>База данных</h3>
44
<h3>База данных</h3>
45
<p>Данные в этом примере поместим в переменную JSON. В реальных проектах данные обычно хранятся в БД. В тестовом проекте данные хранятся в index.js. Вот они:</p>
45
<p>Данные в этом примере поместим в переменную JSON. В реальных проектах данные обычно хранятся в БД. В тестовом проекте данные хранятся в index.js. Вот они:</p>
46
<p>Теперь можно перейти к работе с сервером GraphQL.</p>
46
<p>Теперь можно перейти к работе с сервером GraphQL.</p>
47
<h3>Схема</h3>
47
<h3>Схема</h3>
48
<p>Работа с сервером GraphQL всегда начинается с разработки схемы (Schema). Она состоит из двух взаимосвязанных объектов: TypeDefs и Resolvers.</p>
48
<p>Работа с сервером GraphQL всегда начинается с разработки схемы (Schema). Она состоит из двух взаимосвязанных объектов: TypeDefs и Resolvers.</p>
49
<p>Выше были описаны основные типы GraphQL. Чтобы сервер мог с ними работать, эти типы необходимо определить. Объект typeDef определяет список типов, которые доступны в проекте. Код выглядит так:</p>
49
<p>Выше были описаны основные типы GraphQL. Чтобы сервер мог с ними работать, эти типы необходимо определить. Объект typeDef определяет список типов, которые доступны в проекте. Код выглядит так:</p>
50
<p>В примере выше определяется тип User, в котором указываются fname, age, likes и другие данные. Для каждого поля определяется тип данных: String или Int. GraphQL поддерживает четыре типа данных: String, Int, Float, Boolean. Если в поле указан восклицательный знак, оно становится обязательным.</p>
50
<p>В примере выше определяется тип User, в котором указываются fname, age, likes и другие данные. Для каждого поля определяется тип данных: String или Int. GraphQL поддерживает четыре типа данных: String, Int, Float, Boolean. Если в поле указан восклицательный знак, оно становится обязательным.</p>
51
<p>Также в примере выше определяются типы Query,Mutation и Subscription.</p>
51
<p>Также в примере выше определяются типы Query,Mutation и Subscription.</p>
52
<p>Первый тип, который содержит внутри себя тип Query, называется users. Он принимает id и возвращает объект с данными соответствующего пользователя. Это обязательное поле. Ещё один тип Query называется posts. Он устроен так же, как users.</p>
52
<p>Первый тип, который содержит внутри себя тип Query, называется users. Он принимает id и возвращает объект с данными соответствующего пользователя. Это обязательное поле. Ещё один тип Query называется posts. Он устроен так же, как users.</p>
53
<p>Тип Mutation называется incrementLike. Он принимает параметр fname и возвращает список пользователей.</p>
53
<p>Тип Mutation называется incrementLike. Он принимает параметр fname и возвращает список пользователей.</p>
54
<p>Тип Subscription называется listenLikes. Он возвращает список пользователей.</p>
54
<p>Тип Subscription называется listenLikes. Он возвращает список пользователей.</p>
55
<p>После определения типов необходимо добавить их логику. Это нужно, чтобы сервер знал, как отвечать на запросы клиента. Эта задача решается с помощью Resolvers.</p>
55
<p>После определения типов необходимо добавить их логику. Это нужно, чтобы сервер знал, как отвечать на запросы клиента. Эта задача решается с помощью Resolvers.</p>
56
<blockquote><h3>Также полезно</h3>
56
<blockquote><h3>Также полезно</h3>
57
<p><a>Когда Gatsby заменит WordPress</a>: интервью с GraphQL-гуру Михаилом Новиковым.</p>
57
<p><a>Когда Gatsby заменит WordPress</a>: интервью с GraphQL-гуру Михаилом Новиковым.</p>
58
</blockquote><h3>Resolver</h3>
58
</blockquote><h3>Resolver</h3>
59
<p>Resolver или распознаватель - функция, которая возвращает данные для определённого поля. Resolver’ы возвращают данные того типа, который определён в схеме. Распознаватели могут быть асинхронными. С их помощью можно получать данные из REST API, базы данных или другого источника.</p>
59
<p>Resolver или распознаватель - функция, которая возвращает данные для определённого поля. Resolver’ы возвращают данные того типа, который определён в схеме. Распознаватели могут быть асинхронными. С их помощью можно получать данные из REST API, базы данных или другого источника.</p>
60
<p>Определим Resolver’ы:</p>
60
<p>Определим Resolver’ы:</p>
61
<p>В примере выше есть шесть функций:</p>
61
<p>В примере выше есть шесть функций:</p>
62
<ul><li>запрос users возвращает объект пользователя, соответствующий переданному id;</li>
62
<ul><li>запрос users возвращает объект пользователя, соответствующий переданному id;</li>
63
<li>запрос posts возвращает объект поста, соответствующий переданному id;</li>
63
<li>запрос posts возвращает объект поста, соответствующий переданному id;</li>
64
<li>в поле posts User распознаватель принимает данные пользователя и возвращает список его постов;</li>
64
<li>в поле posts User распознаватель принимает данные пользователя и возвращает список его постов;</li>
65
<li>в поле user Posts функция принимает данные поста и возвращает пользователя, который опубликовал пост;</li>
65
<li>в поле user Posts функция принимает данные поста и возвращает пользователя, который опубликовал пост;</li>
66
<li>мутация incrementLike изменяет объект users: увеличивает количество likes для пользователя с соответствующим fname. После этого users публикуются в pubsub с названием LIKES;</li>
66
<li>мутация incrementLike изменяет объект users: увеличивает количество likes для пользователя с соответствующим fname. После этого users публикуются в pubsub с названием LIKES;</li>
67
<li>подписка listenLikes слушает LIKES и отвечает при обновлении pubsub.</li>
67
<li>подписка listenLikes слушает LIKES и отвечает при обновлении pubsub.</li>
68
</ul><p>Два слова о pubsub. Этот инструмент представляет собой систему передачи информации в режиме реального времени с использованием вебсокетов. pubsub удобно использовать, так как всё, что касается вебсокетов, вынесено в отдельные абстракции.</p>
68
</ul><p>Два слова о pubsub. Этот инструмент представляет собой систему передачи информации в режиме реального времени с использованием вебсокетов. pubsub удобно использовать, так как всё, что касается вебсокетов, вынесено в отдельные абстракции.</p>
69
<p>Итак, работа с типами и распознавателями завершена. Теперь можно запустить сервер.</p>
69
<p>Итак, работа с типами и распознавателями завершена. Теперь можно запустить сервер.</p>
70
<p><em>Запускаем сервер</em></p>
70
<p><em>Запускаем сервер</em></p>
71
<p>Откройте<a>http://localhost:4000/</a>в браузере. Благодаря Apollo вы можете полноценно протестировать сервер GraphQL.</p>
71
<p>Откройте<a>http://localhost:4000/</a>в браузере. Благодаря Apollo вы можете полноценно протестировать сервер GraphQL.</p>
72
<p>Потратили 15 минут на настройку сервера и, вуаля, написали первый запрос. Полная версия кода опубликована<a>здесь</a>.</p>
72
<p>Потратили 15 минут на настройку сервера и, вуаля, написали первый запрос. Полная версия кода опубликована<a>здесь</a>.</p>
73
<h2>REST vs. GraphQL</h2>
73
<h2>REST vs. GraphQL</h2>
74
<p>Что делать, если нам нужно найти пользователя, который опубликовал пост с id x? Рассмотрим, как эта задача решается с помощью REST. Вот данные:</p>
74
<p>Что делать, если нам нужно найти пользователя, который опубликовал пост с id x? Рассмотрим, как эта задача решается с помощью REST. Вот данные:</p>
75
<p>Сначала необходимо определить endpoint’ы GET:</p>
75
<p>Сначала необходимо определить endpoint’ы GET:</p>
76
<p>Когда необходимо получить данные о пользователе, который опубликовал пост с id 1, запрос выглядит так:</p>
76
<p>Когда необходимо получить данные о пользователе, который опубликовал пост с id 1, запрос выглядит так:</p>
77
<p>Чтобы получить нужные данные, приходится дважды обращаться к серверу.</p>
77
<p>Чтобы получить нужные данные, приходится дважды обращаться к серверу.</p>
78
<p>Что делать, если нужно получить только имя пользователя? Конечно, можно использовать данные поля fname. Но мы уже получили дополнительные данные: id, likes, age. Операция становится слишком дорогой.</p>
78
<p>Что делать, если нужно получить только имя пользователя? Конечно, можно использовать данные поля fname. Но мы уже получили дополнительные данные: id, likes, age. Операция становится слишком дорогой.</p>
79
<p>Можно попробовать использовать endpoint, который получает только данные из поля fname:</p>
79
<p>Можно попробовать использовать endpoint, который получает только данные из поля fname:</p>
80
<p>Это решает проблему. Но сложность в том, что вам придётся создавать endpoint для каждого типа информации. Это неудобно.</p>
80
<p>Это решает проблему. Но сложность в том, что вам придётся создавать endpoint для каждого типа информации. Это неудобно.</p>
81
<p>Давайте посмотрим, как можно решить задачу с помощью GraphQL. Всё, что вам требуется - простой запрос:</p>
81
<p>Давайте посмотрим, как можно решить задачу с помощью GraphQL. Всё, что вам требуется - простой запрос:</p>
82
<p>Если нужно получить age пользователя, который опубликовал пост с id 1, запрос будет таким:</p>
82
<p>Если нужно получить age пользователя, который опубликовал пост с id 1, запрос будет таким:</p>
83
<p>Поле user в запросе определено в схеме. Поэтому вы можете получать нужную информацию без использования endpoint’ов и повторных обращений к серверу.</p>
83
<p>Поле user в запросе определено в схеме. Поэтому вы можете получать нужную информацию без использования endpoint’ов и повторных обращений к серверу.</p>
84
<h2>Заключение</h2>
84
<h2>Заключение</h2>
85
<p>В руководстве рассмотрена базовая информация о GraphQL: краткая теория, типы, отличия от REST. В комментариях можно поделиться впечатлениями о GraphQL и опытом применения этого инструмента.</p>
85
<p>В руководстве рассмотрена базовая информация о GraphQL: краткая теория, типы, отличия от REST. В комментариях можно поделиться впечатлениями о GraphQL и опытом применения этого инструмента.</p>
86
<p><em>Адаптированный перевод статьи<a>So, What the Heck is GraphQL</a>by Karthik Kalyanaraman. Мнение автора оригинальной публикации может не совпадать с мнением администрации "Хекслета".</em></p>
86
<p><em>Адаптированный перевод статьи<a>So, What the Heck is GraphQL</a>by Karthik Kalyanaraman. Мнение автора оригинальной публикации может не совпадать с мнением администрации "Хекслета".</em></p>