Работа с GraphQL
Работа с GraphQL и интеграция с front-end приложениями
Last updated
Работа с GraphQL и интеграция с front-end приложениями
Last updated
В этой статье мы познакомимся с одним очень полезным инструментом для качественного и быстрого построения современных веб-приложений. Как вы уже могли догадаться из названия, речь пойдет про GraphQL. Эту статью можно использовать в качестве учебного материала для тех, кто еще не знаком с данной технологией. Помимо этого, она отлично подойдет вам, если вы хотите освежить в памяти уже имеющиеся знания. Кто знает, может и опытные специалисты узнают тут что-то новое?
Сейчас мы узнаем, что же такое GraphQl, сравним его с REST API, узнаем как им правильно пользоваться, выделим основные преимущества и недостатки. Ну и конечно, на примерах узнаем как работает GraphQL и какие у него возможности.
Если брать определение из интернета, то мы узнаем, что — это язык запросов и серверная среда для API с открытым исходным кодом. Однако, если немного абстрагироваться от этого определения и вникнуть в суть названия, то можно задать себе вопрос: почему именно Graph? Потому что он представляет собой структуру данных в виде графа, где узлы графа представляют собой объекты, а рёбра - связи между этими объектами.
Теперь, когда мы поняли, что такое GraphQL, необходимо узнать, кто и зачем его все-таки создал. Ну и, конечно же, очередная инновация в свое время пришла, чтобы решить какую-либо проблему. Когда разработчики Facebook создавали мобильное приложение, они искали способы ускорить работу. Была трудность: при одновременном запросе из различных по типу баз данных, например из облачной Redis и MySQL, приложение ужасно тормозило. Для решения задачи в Facebook придумали собственный язык запросов, который обращается к конечной точке и упрощает форму запрашиваемых данных. Особенно это было актуально для социальной сети, где много связей и запросов по связанным элементам. Например, получить посты всех подписчиков пользователя X.
В 2015 году код GraphQL стал открытым, и сейчас его используют Airbnb, GitHub, Pinterest, Shopify и многие другие компании.
Как мы уже поняли, GraphQL был создан как альтернатива Rest API, чтобы решать некоторые его недостатки. В таком случае возникает вопрос: почему все не перейдут на GraphQL? Оба метода имеют свои преимущества и недостатки, и понимание различий между ними является ключевым шагом при проектировании эффективного и масштабируемого веб-сервиса. Давайте рассмотрим основные характеристики и особенности каждого подхода, чтобы принять взвешенное решение в пользу того, что лучше соответствует требованиям нашего проекта.
REST - хорошая штука, но у него есть некоторые проблемы с которыми и столкнулся Facebook:
1) Во-первых, это избыточность или недостаток данных в ответе. В REST API клиенты часто получают либо слишком много данных, которые им не нужны, либо слишком мало, что вынуждает делать несколько запросов для получения необходимой информации. GraphQL позволяет клиентам запрашивать только те данные, которые им нужны, и получать их в одном запросе, что делает коммуникацию более эффективной.
2) Также в REST API каждый эндпоинт обычно соответствует определенному ресурсу, что может привести к проблемам с расширяемостью и поддержкой разных версий API. В GraphQL же существует единая конечная точка для всех запросов, и схема API определяется на стороне сервера. Это делает API более гибким и облегчает его развитие.
3) Ну а также во многих REST API при работе со связанными данными возникает проблема "N+1 запросов", когда для получения связанных данных нужно делать дополнительные запросы к серверу. GraphQL позволяет выразить связи между данными и получать все необходимые данные в одном запросе. Для большего понимания различий между этими двумя подходами, давайте рассмотрим пример. Предположим, нам нужно найти пользователя, который оставил первый комментарий под постом с id x?
Попробуем решить эту задачу с использованием REST. Сначала необходимо определить эндпоинты GET:
>
>
Теперь, если мы хотим получить данные о пользователе, который опубликовал первый комментарий к посту с id 1, нам необходимо выполнить следующие запросы:
Для получения конкретных данных нам необходимо делать два запроса, это не очень удобно, не правда ли? При этом, если нам требуется узнать только имя пользователя, то в ответе мы получаем лишние данные (age, likes, id), а в масштабах крупного приложения с большим трафиком это может очень дорого обойтись.
Теперь давайте рассмотрим решение этой задачи при помощи GraphQL. Всё, что нам потребуется, это простой запрос:
При этом, если нам потребуется другое поле, например age, то можно просто поменять fname на age. Теперь нам не нужно создавать новые эндпоинты или делать лишние запросы.
GraphQL позволяет клиентам запрашивать только ту информацию, что им нужна. Это уменьшает время ответа от сервера и количество данных, которые нужно передавать по сети. Однако, необходимо учитывать и недостатки этого инструмента.
Он позволяет запрашивать, вот только может сильно увеличить время ответа сервера. Это как с прямыми SQL запросами. Много сложности тут перекладывается на плечи разработчика сервера. То есть никак не отменяет необходимости мероприятий по оптимизации. А еще открывает кучу дыр, которые потом требуется затыкать. Если вы делаете что-то массовое, GraphQL сильно поднимает требования к уровню разработчиков.
Подводя итоги данного сравнения, необходимо помнить, что у каждого метода есть свои преимущества и недостатки. Выбор между REST API и GraphQL зависит от конкретных требований проекта, типа данных, и степени гибкости, которую разработчики хотят получить. GraphQL предоставляет более гибкий и эффективный способ взаимодействия с данными, но также может потребовать больше управления. Его оптимально использовать в том случае, когда мы можем пожертвовать сложностью управления ради быстродействия. В свою очередь, REST API остается широко используемым и хорошо зарекомендовавшим себя методом для многих приложений.
GraphQL работает на принципе графа, что отражает способ организации данных и запросов, клиенты могут запрашивать связанные данные, а также только те данные, которые им нужны. Теперь разберемся, как нам получать доступ к нужному графу. Для определенных операций над графом существуют специальные запросы. Типы запросов в GraphQL сводятся к основным трём:
Query
Mutation
Subscription
Тип запроса Query в GraphQL — аналог GET в REST. Запросы — строки, которые отправляются в теле HTTP POST-запроса.
Примечание — Обратите внимание, все типы запросов в GraphQL отправляются через POST.
Query описывает данные, которые необходимо получить с сервера. Например, с помощью кода ниже можно получить поля fname и age всех пользователей в базе данных.
В ответ на этот запрос сервер присылает данные в формате JSON. Структура ответа соответствует структуре запроса.
Успешные операции возвращают JSON с ключом "data" и с ключом "error", а неуспешные возвращают JSON с ключом и сообщением об ошибке. Благодаря этому удобно обрабатывать ошибки на стороне клиента.
Для Query запросов часто используются псевдонимы (Aliases) – инструмент, позволяющий переименовывать поля в теле ответа. Это полезно, когда вы хотите получить данные из нескольких полей с одинаковыми именами, но хотите, чтобы они имели разные имена в ответе. Вот пример запроса GraphQL с использованием алиасов:
Так мы в ответе можем отличить имя и описание продукта от имени и описания пользователя.
Также в GraphQL существуют переменные (Variables), которые используются для динамического указания значения в запросе. Давайте подробнее разберемся на примере:
Здесь GetAccHolder является именованной функцией. Полезно использовать именованную функцию, когда у вас много запросов в вашем приложении.
Потом мы задекларировали переменную $id с типом String. Ну а дальше уже также, как и в нашем изначальном запросе, но вместо фиксированного id, мы в запросе отдали переменную $id.
Mutation — ещё один root types. С его помощью можно добавлять данные в БД. Mutation — аналог POST и PUT в REST. Ниже пример кода.
Здесь создаётся мутация createUser, которая добавляет в БД пользователя с fname Richie и age 22. В круглых скобках мы передаем аргументы для указания конкретного пользователя, которого мы хотим создать. Аргументы могут использоваться в различных запросах для множества целей. В ответ на этот запрос сервер присылает JSON с id записи. Ответ выглядит так:
Subscription — третий тип операций в GraphQL. С его помощью клиент слушает изменения в БД в режиме реального времени. Под капотом подписки используют вебсокеты. Пример кода:
С помощью этого запроса можно получать список пользователей с именами и количеством лайков каждый раз, когда оно меняется.
Например, когда пользователь с fname Richie получает лайк, ответ будет таким:
Подобный запрос можно использовать для обновления количества лайков в режиме реального времени в соответствующем интерфейсе, например, в форме с результатами голосования на сайте.
Перед тем, как изучать работу с сервером, необходимо разобраться с типами, которые определены в GraphQL. Они нам нужны для правильного построения схемы, но об этом – позже. Список типов:
Скалярный тип
Тип объекта
Тип запроса и мутации
Типы ввода
Тип перечисления
Союз и интерфейс
В данной системе типизации также присутствует модификатор ненулевого значения(!). Это означает, что мы можем отмечать поля, которые обязаны иметь ненулевое значение, восклицательным знаком. Если каким-то образом сервер получит нулевое значение для такого поля, то пользователь узнает об ошибке. Ну и конечно, мы можем использовать массив в качестве типа определенного поля при помощи квадратных скобок.
Скалярные типы представляют собой примитивные типы данных для таких полей, как строки, целые числа и т. д. Эти типы не могут иметь дополнительных вложенных подполей. Вот скалярные типы, поддерживаемые GraphQL:
Int: 32-битное целое число со знаком.
Float: Знаковое значение двойной точности с плавающей запятой.
String: последовательность символов UTF-8.
Boolean: правда или ложь.
ID: Скалярный тип ID представляет собой уникальный идентификатор и сериализуется в виде строки.
Каждый запрос также должен быть описан в схеме, поэтому для них существует отдельный тип.
Например:
Эта схема GraphQL определяет тип запроса с одним полем с именем getAllUsers. Запрос getAllUsers выводит массив объектов User. Это означает, что когда клиент отправляет запрос getAllUsers на сервер, он получит список всех пользователей в системе.
Тип Query определяет все точки входа для операций чтения, аналогично существует тип Mutation, который определяет точки входа для операций записи на вашем сервере GraphQL.
Например:
Эта схема GraphQL определяет тип Mutation, который имеет одно поле с именем addUser. Поле addUser принимает два аргумента: имя и адрес электронной почты, оба имеют тип String. Когда клиент вызывает это поле мутации с допустимыми значениями имени и адреса электронной почты, новый объект «Пользователь» создается с предоставленными данными и добавляется в систему. Мутация addUser возвращает вновь созданный объект User.
Большинство определяемых типов в схеме GraphQL будут объектными. Они представляют из себя обычный объект из JS с полями скалярных типов.
Типы входных данных — это типы, которые будут определять тип данных аргументов в ваших запросах и мутациях. Типы ввода такие же, как и типы объектов, с той лишь разницей, что для определения типа ввода мы используем ключевое слово input вместо type.
Типы ввода очень полезны, когда вы хотите передавать объекты в качестве аргументов вашего запроса или мутации вместо скаляров. Например, в addUser приведенной выше мутации, если вы хотите передать пользовательский объект в качестве аргумента, вы можете определить тип ввода и мутацию следующим образом:
Тип перечисление похож на скалярный тип, но все его допустимые значения определены в самой схеме. Перечисления наиболее полезны в ситуациях, когда пользователю приходится выбирать из заданного списка опций.
В GraphQL также можно использовать интерфейсы. Суть у них такая же, как и в обычном программировании. Интерфейс определяет набор полей, которые могут быть реализованы несколькими другими типами объектов; когда тип объекта реализует интерфейс, он должен включать все поля интерфейса, а также может включать дополнительные поля.
Союзы в свою очередь используются для того, чтобы определить для поля несколько возможных типов. При этом важно заметить, что при помощи союзов мы можем объединять только объектные типы.
union SearchResult = Movie | Music
Работа с сервером GraphQL всегда начинается с разработки схемы, в которой описывается структура данных, логика работы и типы. Теперь, когда мы разобрались с типами, это не составит никаких проблем. Схема используется для проверки и выполнения запроса, когда он поступает на сервер со стороны клиента. После обработки запроса клиенту отправляются запрошенные данные или ошибки, в зависимости от результатов. Схема состоит из двух взаимосвязанных объектов: TypeDefs и Resolvers.
Объект typeDef определяет список типов, которые доступны в проекте. Код выглядит так:
После определения типов необходимо добавить их логику. Это нужно, чтобы сервер знал, как отвечать на запросы клиента. Эта задача решается с помощью Resolvers.
Resolver или распознаватель — функция, которая возвращает данные для определенного поля. Resolver возвращает данные того типа, который определен в схеме. Распознаватели могут быть асинхронными. С их помощью можно получать данные из REST API, базы данных или другого источника.
В примере выше есть шесть функций:
запрос users возвращает объект пользователя, соответствующий переданному id;
запрос posts возвращает объект поста, соответствующий переданному id;
в поле posts User распознаватель принимает данные пользователя и возвращает список его постов;
в поле user Posts функция принимает данные поста и возвращает пользователя, который опубликовал пост;
мутация incrementLike изменяет объект users: увеличивает количество likes для пользователя с соответствующим fname. После этого users публикуются в pubsub с названием LIKES;
подписка listenLikes слушает LIKES и отвечает при обновлении pubsub.
Теперь давайте подведем итоги изученного материала и сделаем выжимку. GraphQL – это язык запросов и серверная среда для API с открытым исходным кодом, созданная компанией Facebook как решение проблем, возникавших с использованием REST API. GraphQL позволяет клиентам запрашивать только ту информацию, что им нужна. Это уменьшает время ответа от сервера и количество данных, которые нужно передавать по сети. Один из главных недостатков – увеличение нагрузки на сервер и увеличение сложности управления. Для работы с GraphQL существует 3 основных типа запросов:
Query
Mutation
Subscription
Для описания сервера необходимо разработать схему – файл, в котором прописывается логика работы GraphQL API, типы и структура данных. Схема состоит из двух взаимосвязанных объектов: TypeDefs и Resolvers. Объект typeDef определяет список типов, которые доступны в проекте. Основные типы GraphQL:
Скалярный тип
Тип объекта
Тип запроса и мутации
Типы ввода
Тип перечисления
Союз и интерфейс
Resolver или распознаватель — функция, которая возвращает данные для определенного поля. Resolver возвращает данные того типа, который определен в схеме.
– платформа для подробного изучения каждого аспекта GraphQL
– новая статья с habr
– официальная сайт graphQL
– старая статья с habr
- статья на хекслет
– репозиторий с примером сервера graphql
– видео про GraphQL и React, создание простого приложения
– репозиторий с приложением React + GraphQL + Express