Resolver — это набор функций, которые генерируют ответ на запрос GraphQL. Проще говоря, распознаватель действует как обработчик запросов GraphQL. Каждая функция распознавателя в схеме GraphQL принимает четыре позиционных аргумента, как показано ниже:
Пример функций распознавателя показан ниже —
Ниже приведены позиционные аргументы и их описание.
Sr.No.
Аргументы и описание
1
Объект, который содержит результат, возвращаемый распознавателем в родительском поле.
Объект с аргументами, переданными в поле в запросе.
Этот объект является общим для всех распознавателей в конкретном запросе.
Он содержит информацию о состоянии выполнения запроса, включая имя поля, путь к полю от корня.
Объект, который содержит результат, возвращаемый распознавателем в родительском поле.
Объект с аргументами, переданными в поле в запросе.
Этот объект является общим для всех распознавателей в конкретном запросе.
Он содержит информацию о состоянии выполнения запроса, включая имя поля, путь к полю от корня.
Resolver Result Format
Решатели в GraphQL могут возвращать различные типы значений, как указано ниже —
Sr.No.
Аргументы и описание
1
нулевой или неопределенный
это указывает на то, что объект не может быть найден
это допустимо, только если схема указывает, что результатом поля должен быть список
распознаватели часто выполняют асинхронные действия, такие как выборка из базы данных или бэкэнд-API, поэтому они могут возвращать обещания
распознаватель также может возвращать другие значения
нулевой или неопределенный
это указывает на то, что объект не может быть найден
это допустимо, только если схема указывает, что результатом поля должен быть список
распознаватели часто выполняют асинхронные действия, такие как выборка из базы данных или бэкэнд-API, поэтому они могут возвращать обещания
распознаватель также может возвращать другие значения
иллюстрация
Давайте создадим простое приложение для понимания решателя. Это создаст схему для запроса студента по идентификатору с сервера. Данные об учениках будут храниться в плоском файле, и мы будем использовать модуль узла notarealdb для подделки базы данных и чтения из плоского файла.
Ниже приведен пошаговый процесс создания простого приложения:
Шаг 1 — Загрузите и установите необходимые зависимости для проекта
Шаг 2 — Создание схемы
Добавьте файл schema.graphql в папку проекта resolver-app и добавьте следующий код —
Шаг 3 — Создание резольвера
Создайте файл resolvers.js в папке проекта и добавьте следующий код —
Здесь studentById принимает три параметра. Как обсуждалось в этой главе, studentId может быть получен из аргументов; root будет содержать сам объект Query. Чтобы вернуть конкретного студента, нам нужно вызвать метод get с параметром id в коллекции студентов.
Здесь приветствие, Students, studentById являются резольверами, которые обрабатывают запрос. Функция распознавания студентов возвращает список студентов из слоя доступа к данным. Чтобы получить доступ к функциям распознавателя вне модуля, объект Query должен быть экспортирован с помощью module.exports.
Шаг 4 — Запустите приложение
Создайте файл server.js. См. Шаг 8 в главе «Настройка среды». Выполните команду npm start в терминале. Сервер будет работать на 9000 портов. Здесь мы используем GraphiQL в качестве клиента для тестирования приложения.
Выходные данные для вышеупомянутого запроса как показано ниже —
Вашему вниманию предлагаю перевод статьи Sacha Greif «Что же такое этот GraphQL?»
Если вы такой же, как и я, вы обычно проходите через три этапа, когда узнаёте о новой технологии:
Есть одна хитрость для поддержания благоразумия в эпоху быстроразвивающихся технологий: изучать новые вещи между вторым и третьим этапом, как только интерес задет, но пока технология ещё не распространена повсеместно.
Именно поэтому сейчас самое время узнать, что же такое этот GraphQL, о котором вы повсюду слышите.
Основы
В двух словах, GraphQL это синтаксис, который описывает как запрашивать данные, и, в основном, используется клиентом для загрузки данных с сервера. GraphQL имеет три основные характеристики:
Так с чего же начать изучение GraphQL? Как это выглядит на практике? Как начать его использовать? Читайте дальше чтобы узнать!
Задача
GraphQL был разработан в большом старом Facebook, но даже гораздо более простые приложения могут столкнуться с ограничениями традиционных REST API интерфейсов.
Но затем, при разработке мобильного приложения, оказалось что из-за загрузки дополнительных данных приложение работает медленнее. Так что вам теперь нужно два endpoint, один возвращающий записи с лайками, а другой без них.
Добавим ещё один фактор: оказывается, записи хранятся в базе данных MySQL, а лайки в Redis! Что же теперь делать?!
Экстраполируйте этот сценарий на то множество источников данных и клиентских API, с которыми имеет дело Facebook, и вы поймёте почему старый добрый REST API достиг своего предела.
Решение
Facebook придумал концептуально простое решение: вместо того, чтобы иметь множество «глупых» endpoint, лучше иметь один «умный» endpoint, который будет способен работать со сложными запросами и придавать данным такую форму, какую запрашивает клиент.
Фактически, слой GraphQL находится между клиентом и одним или несколькими источниками данных; он принимает запросы клиентов и возвращает необходимые данные в соответствии с переданными инструкциями. Запутаны? Время метафор!
Пользоваться старой REST-моделью это как заказывать пиццу, затем заказывать доставку продуктов, а затем звонить в химчистку, чтобы забрать одежду. Три магазина – три телефонных звонка.
GraphQL похож на личного помощника: вы можете передать ему адреса всех трех мест, а затем просто запрашивать то, что вам нужно («принеси мне мою одежду, большую пиццу и два десятка яиц») и ждать их получения.
Другими словами, GraphQL это стандартный язык для разговора с этим волшебным личным помощником.
Согласно Google Images, типичный личный помощник это пришелец с восемью руками
На практике GraphQL API построен на трёх основных строительных блоках: на схеме (schema), запросах (queries) и распознавателях (resolvers).
Запросы (queries)
(query и request одинаково переводится как «запрос». Далее будет подразумеваться query, если не указано иначе – прим. пер.)
Когда вы о чём-то просите вашего персонального помощника, вы выполняете запрос. Это выглядит примерно так:
Как можно заметить, клиенту при формировании запроса не нужно знать откуда поступают данные. Он просто спрашивает о них, а сервер GraphQL заботится об остальном.
Также стоит отметить, что поля запроса могут быть массивами. Например вот общий шаблон запроса списка сообщений:
Поля запроса также могут содержать аргументы. Например, если необходимо отобразить конкретный пост, можно добавить аргумент id к полю post :
Наконец, если нужно сделать аргумент id динамическим, можно определить переменную, а затем использовать её в запросе (обратите внимание, также мы сделали запрос именованным):
Хороший способ попробовать все это на практике – использовать GraphQL API Explorer от GitHub. Например, давайте попробуем выполнить следующий запрос:
GraphQL и автодополнение в действии
Обратите внимание, когда вы вводите имя поля, IDE автоматически предлагает вам возможные имена полей, полученные при помощи GraphQL API. Ловко!
Анатомия запросов GraphQL (англ)
Вы можете узнать больше о запросах GraphQL в отличной статье «Анатомия запросов GraphQL» (англ).
Распознаватели (resolvers)
Даже самый лучший в мире личный помощник не сможет принести ваши вещи из химчистки если вы не дадите ему адрес.
Подобным образом, сервер GraphQL не может знать что делать с входящим запросом, если ему не объяснить при помощи распознавателя (resolver).
Используя распознаватель GraphQL понимает, как и где получить данные, соответствующие запрашиваемому полю. К примеру, распознаватель для поля запись может выглядеть вот так (используя генератор схемы (schema) из набора Apollo GraphQL-Tools):
Мы помещаем наш распознаватель в раздел Query потому что мы хотим получать запись ( post ) в корне ответа. Но также мы можем создать распознаватели для подполей, как например для поля author :
Обратите внимание что ваши распознаватели не ограничены в количестве возвращаемых объектов. К примеру, вы захотите добавить поле commentsCount к объекту Post :
Как было показано выше, вы можете писать любой код внутри распознавателя. Так что вы можете изменять содержимое базы данных; такие распознаватели называют изменяющими (mutation).
Схема (schema)
Все это становится возможным благодаря типизированной схеме данных GraphQL. Цель этой статьи дать скорее краткий обзор, чем исчерпывающее введение, так что в этом разделе не будет подробностей.
Я призываю вас заглянуть в документацию GraphQL (англ), если вы хотите узнать больше.
Часто задаваемые вопросы
Сделаем перерыв, чтобы ответить на несколько общих вопросов.
Эй, вы там, на задних рядах. Да вы. Я вижу, вы хотите что-то спросить. Идите вперед, не стесняйтесь!
Что общего у GraphQL и графовых баз данных?
Ничего общего. На самом деле, GraphQL не имеет ничего общего с графовыми БД типа Neo4j. Часть «Graph» отражает идею получения контента, проходя сквозь граф API, используя поля и подполя; часть «QL» расшифровывается как «query language» – «язык запросов».
Меня полностью устраивает REST, зачем мне переходить на GraphQL?
Если вы не достигли болевых точек REST API, решением которых является GraphQL, то можете не волноваться.
Использование GraphQL поверх REST вероятнее всего не заставит вас производить какие-то сложные изменения в остальном API и ломать накопившийся пользовательский опыт, так что переход не будет вопросом жизни и смерти в любом случае. Так что определенно стоит попробовать GraphQL в небольшой части проекта, если это возможно.
Могу ли я использовать GraphQL без React/Relay/имя_библиотеки?
Конечно! GraphQL это только спецификация, вы можете использовать его с любой библиотекой на любой платформе, используя готовый клиент (к примеру, у Apollo есть клиенты для web, iOS, Angular и другие) или вручную отправляя запросы на сервер GraphQL.
GraphQL был создан Facebook, а я не доверяю Facebook.
Ещё раз, GraphQL является всего лишь спецификацией, это значит что вы можете использовать его не используя ни одной строки кода, написанной Facebook.
Наличие поддержки Facebook это безусловно хороший плюс для экосистемы GraphQL. Но на данный момент сообщество достаточно большое чтобы поддерживать GraphQL, даже если Facebook перестанет его использовать.
Как-то «позволить клиенту просить о тех данных, которые ему нужны» не выглядит безопасным
Так как вы пишете свои распознаватели, вы можете разрешать любые проблемы безопасности на этом уровне.
К примеру, если вы позволите клиенту использовать параметр limit для указания количества документов, которые он запрашивает, вы скорее всего захотите контролировать это число для избежания атак типа «отказ в обслуживании» когда клиент будет запрашивать миллионы документов снова и снова.
Так что же нужно чтобы начать?
На самом деле, необходимо всего два компонента чтобы начать:
Теперь, когда вы понимаете как работает GraphQL, можно поговорить о главных игроках в этой области.
Серверы GraphQL
Первое что вам нужно для работы, это сервер GraphQL. Сам GraphQL это просто спецификация, так что двери открыты для конкурирующих реализаций.
GraphQL-JS (Node)
Это ссылка на оригинальную реализацию спецификации GraphQL. Вы можете использовать её с express-graphql для создания своего сервера API (англ).
GraphQL-Server (Node)
Команда Apollo имеет свою собственную реализацию GraphQL-сервера. Она ещё не настолько полна как оригинал, но очень хорошо документирована, хорошо поддерживается и быстро развивается.
Другие платформы
Клиенты GraphQL
Конечно вы можете работать с API GraphQL напрямую, но специальная клиентская библиотека определённо может сделать вашу жизнь проще.
Relay
Relay это собственный инструментарий Facebook. Он создавался с учётом потребностей Facebook и может быть немного избыточным для большинства пользователей.
Клиент Apollo
Быстро занял своё место новый участник в этой области — Apollo. Типичный клиент состоит из двух частей:
По умолчанию Apollo-client сохраняет данных используя Redux, который сам является достаточно авторитетной библиотекой управления состоянием с богатой экосистемой.
Расширение Apollo для Chrome DevTools
Приложения с открытым исходным кодом
Несмотря на то, что GraphQL это достаточно новая концепция, уже есть некоторые перспективные приложения с открытым исходным кодом, которые используют её.
VulcanJS
Я (автор оригинальной статьи — прим. пер.) являюсь ведущим разработчиком VulcanJS. Я создал его чтобы дать людям возможность попробовать силу стека React/GraphQL без необходимости писать много шаблонного кода. Вы можете воспринимать его как «Rails для современной web-экосистемы» потому что он позволяет создавать CRUD-приложения (клон Instagram например) в течение нескольких часов.
Gatsby
Gatsby это генератор статических сайтов для React, который начиная с версии 1.0 также использует GraphQL. Несмотря на то, что это можно показаться странным сочетанием на первый взгляд, это на самом деле довольно мощная идея. В процессе сборки Gatsby может извлекать данные из нескольких GraphQL API, затем используя их для создания полностью статического клиентского React-приложения.
Другие инструменты для работы с GraphQL
GraphiQL
GraphiQL это очень удобная браузерная IDE для создания и выполнения запросов к endpoint-ам GraphQL.
DataLoader
Из-за вложенной природы запросов GraphQL, один запрос может легко вызывать десятки обращений к базе данных. Для снижения нагрузки вы можете использовать инструменты кеширования наподобие разработанной Facebook библиотеке DataLoader.
Create GraphQL Server
Create GraphQL Server это консольная программа, позволяющая легко и быстро сгенерировать сервер на базе Node, использующий базу данных Mongo.
GraphQL-up
Аналогично Create GraphQL Server, GraphQL-up позволяет быстро создать GraphQL backend, но на базе сервиса Graphcool.
Сервисы GraphQL
Наконец, есть целый ряд компаний, предоставляющих «GraphQL-backend-как-сервис»; они сами позаботятся о серверной части для вас, и это может быть хорошим способом окунуться в экосистему GraphQL.
Graphcool
Гибкая backend-платформа, объединяющая GraphQL и AWS Lambda, имеющая бесплатный тарифный план для разработки.
Scaphold
Другой GraphQL-backend-как-сервис с бесплатным тарифным планом. Он предлагает много функций, подобных Graphcool.
Уже есть немало ресурсов по GraphQL.
(Также предлагайте ресурсы на русском языке в комментариях – прим. пер.)
GraphQL.org (англ)
На официальном сайте GraphQL есть замечательная документация чтобы начать.
LearnGraphQL (англ)
LearnGraphQL это интерактивный курс, созданный в компании Kadira.
LearnApollo (англ)
Хорошее продолжение LearnGraphQL, LearnApollo это бесплатный курс, созданный Graphcool.
Блог Apollo (англ)
Блог Apollo имеет массу подробных хорошо написанных постов о Apollo и GraphQL в целом.
GraphQL Weekly (англ)
Информационная рассылка о GraphQL, курируемая командой Graphcool.
Hashbang Weekly (англ)
Еще одна большая новостная рассылка, которая помимо GraphQL также охватывает React и Meteor.
Freecom (англ)
Серия руководств, описывающая как создать клон Интерком с помощью GraphQL.
Awesome GraphQL (англ)
Довольно исчерпывающий перечень ссылок и ресурсов по GraphQL.
Как же вы можете применить вновь приобретенные знания о GraphQL на практике? Вот несколько рецептов, которые можно попробовать:
Apollo + Graphcool + Next.js
Если вы уже знакомы с Next.js и React, этот пример позволит вам настроить GraphQL endpoint при помощи Graphcool и затем отправлять ей запросы при помощи Apollo.
VulcanJS
Учебник Vulcan (англ) поможет вам создать простой слой данных GraphQL на сервере и на клиенте. Поскольку Vulcan является платформой «все-в-одном», это хороший способ начать работу без каких-либо настроек. Если вам нужна помощь, не стесняйтесь обратиться в наш канал Slack (англ)!
Учебник GraphQL & React
В блоге Chroma есть руководство из шести частей (англ) по созданию приложения React/GraphQL используя компоненто-ориентированный подход к разработке.
Заключение
GraphQL поначалу может показаться сложным, потому что это технология, которая затрагивает многие области современной разработки. Но уделив время чтобы понять основные концепции, я думаю вы поймёте что многое из этого имеет смысл.
Решите ли вы использовать это или нет, я считаю что стоит потратить время чтобы ознакомиться с GraphQL. Все больше и больше компаний и структур начинают использовать его, и он вполне может в течение следующих нескольких лет стать одним из ключевых строительных блоков в веб-разработке.
Согласны? Не согласны? Вопросы? Дайте мне знать, здесь в комментариях.
After being validated, a GraphQL query is executed by a GraphQL server which returns a result that mirrors the shape of the requested query, typically as JSON.
GraphQL cannot execute a query without a type system, let’s use an example type system to illustrate executing a query. This is a part of the same type system used throughout the examples in these articles:
In order to describe what happens when a query is executed, let’s use an example to walk through.
You can think of each field in a GraphQL query as a function or method of the previous type which returns the next type. In fact, this is exactly how GraphQL works. Each field on each type is backed by a function called the resolver which is provided by the GraphQL server developer. When a field is executed, the corresponding resolver is called to produce the next value.
If a field produces a scalar value like a string or number, then the execution completes. However if a field produces an object value then the query will contain another selection of fields which apply to that object. This continues until scalar values are reached. GraphQL queries always end at scalar values.
Root fields & resolvers#
At the top level of every GraphQL server is a type that represents all of the possible entry points into the GraphQL API, it’s often called the Root type or the Query type.
This example is written in JavaScript, however GraphQL servers can be built in many different languages. A resolver function receives four arguments:
Asynchronous resolvers#
Let’s take a closer look at what’s happening in this resolver function.
The context is used to provide access to a database which is used to load the data for a user by the id provided as an argument in the GraphQL query. Since loading from a database is an asynchronous operation, this returns a Promise. In JavaScript, Promises are used to work with asynchronous values, but the same concept exists in many languages, often called Futures, Tasks or Deferred. When the database returns, we can construct and return a new Human object.
Notice that while the resolver function needs to be aware of Promises, the GraphQL query does not. It simply expects the human field to return something which it can then ask the name of. During execution, GraphQL will wait for Promises, Futures, and Tasks to complete before continuing and will do so with optimal concurrency.
Trivial resolvers#
Now that a Human object is available, GraphQL execution can continue with the fields requested on it.
Resolving the name in this case is very straight-forward. The name resolver function is called and the obj argument is the new Human object returned from the previous field. In this case, we expect that Human object to have a name property which we can read and return directly.
In fact, many GraphQL libraries will let you omit resolvers this simple and will just assume that if a resolver isn’t provided for a field, that a property of the same name should be read and returned.
Scalar coercion#
While the name field is being resolved, the appearsIn and starships fields can be resolved concurrently. The appearsIn field could also have a trivial resolver, but let’s take a closer look:
List resolvers#
We’ve already seen a bit of what happens when a field returns a list of things with the appearsIn field above. It returned a list of enum values, and since that’s what the type system expected, each item in the list was coerced to the appropriate enum value. What happens when the starships field is resolved?
The resolver for this field is not just returning a Promise, it’s returning a list of Promises. The Human object had a list of ids of the Starships they piloted, but we need to go load all of those ids to get real Starship objects.
GraphQL will wait for all of these Promises concurrently before continuing, and when left with a list of objects, it will concurrently continue yet again to load the name field on each of these items.
Producing the result#
As each field is resolved, the resulting value is placed into a key-value map with the field name (or alias) as the key and the resolved value as the value. This continues from the bottom leaf fields of the query all the way back up to the original field on the root Query type. Collectively these produce a structure that mirrors the original query which can then be sent (typically as JSON) to the client which requested it.
Let’s take one last look at the original query to see how all these resolving functions produce a result:
Всем привет, хочу поделиться накопленными знаниями по GraphQL, которые сформировались на основе около сотни прочитанных статей/доков и месяца построения API используя GraphQL.
Ну что ж, начнем с того, что такое GraphQL?
GraphQL — это стандарт декларирования структуры данных и способов получения данных, который выступает дополнительным слоем между клиентом и сервером.
Одной из основных фичей GraphQL является то, что структура и обьем данных определяется клиентским приложением.
Рассмотрим пример простого запроса пользователя.
Клиент точно указывает, какие данные он хочет получить, используя декларативную, графо-подобную структуру, которая очень напоминает формат JSON.
В данном случае клиент запрашивает три поля (name, email и age). Но он может запрашивать как одно поле, к примеру name, так и произвольное количество полей, которые определены в типе user на GraphQL сервере.
В таком подходе, помимо удобства, у нас уменьшается либо количество запросов, либо обьем данных на транспортном уровне.
GraphQL облегчает агрегацию данных из нескольких источников.
У нас есть клиентское приложение и один сервер. Транспорт данных выглядит довольно просто, не важно, какой именно протокол передачи данных для этого используется. В случае http мы посылаем запрос и получаем ответ, все довольно просто.
Как я уже говорил, GraphQL является дополнительным слоем между клиентом и сервером, и если посмотреть на эту архитектуру, то использование GraphQL выглядит вроде как избыточно. Но как только добавляется еще один сервис, все становится на свои места.
Сервисы могут быть написанными на любом языке программирования, взаимодействовать с разными базами данных, Sql или NoSql, могут иметь разные API. Работать при такой архитектуре становиться довольно сложно, а добавление каждого нового сервиса требует много ресурсов.
Это классическая проблема масштабирования проекта, и наверняка при работе с несколькими сервисами вы используете какой либо «API Gateway».
GraphQL и является этим стандартизированным «API Gateway». Транспорт данных клиент-сервер может выполнятся с помощью любого протокола (http, ssh, ws, cli, etc.).
Клиент запрашивает ресурсы у GraphQL сервера используя GraphQL запрос. GraphQL сервер анализирует запрос, рекурсивно проходит по графу и выполняет для каждого поля его «resolver» функцию. Когда все данные по запросу будут собраны, GraphQL сервер вернет ответ.
Важно отметить, что добавление нового сервиса не влияет на существующее приложение. За счет того, что клиент определяет, какие данные он хочет получить, можно не боясь расширять существующие типы.
Система типов
GraphQL использует систему типов для описания данных.
В GraphQL поля могут быть представлены как базовыми, так и пользовательскими типами. В данном примере поле user представлено пользовательским типом User. У типа User описан набор полей, которые представлены базовыми типами.
Таким образом и реализуется графо-подобная структура неопределенного уровня вложенности.
Сравнение GraphQL API и REST API
В GraphQL мы можем описать любой созданный нами тип. Для этого при создании типа нужно в поле «description» описать, для чего данный тип нужен. Эту документацию умеют парсить различные утилиты, IDE, что очень упрощает работу с GraphQL.
Также, GraphQL из коробки имеет свой IDE, который работает в браузере и называется GraphiQL.
GraphiQL хранит историю запросов, подсвечивает синтаксис, подсказывает поля, которые мы можем запросить у текущего типа, парсит документацию. Это заметно упрощает написание запросов.
GraphiQL можно включить через конфигурацию GraphQL, с помощью настройки graphiql = true и перейдя по пути /graphiql. Либо же можно использовать одно из расширений для браузера, которые имеют практически одинаковую функциональность но разный UI.
REST не имеет подобной функциональности, но есть возможность её реализовать используя SWAGGER.
Делая вывод из предыдущих пунктов, вы наверняка уже знаете ответ, за счет того что GraphQL — это единая точка входа то в GraphQL, мы имеем возможность передать аргументы на любой уровень вложенности.
В REST каждый путь представлен как отдельная точка входа, в таком случае передать аргументы мы можем только для всего запроса.
На этом конец первой части, вторая часть добавится в скором времени. Всем спасибо!)