HTML Diff
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>