-Сравнение GraphQL API с REST API, действительно ли GraphQL "убийца" REST?
-Возможные проблемы, сложности и решения при имплементации GraphQL API.
-Плюсы и минусы использования GraphQL API.
-А вам действительно нужен GraphQL API, стоят ли затраты полученного результата?
2. SERVICE
Get User data
Get Posts data
Get Comments data
Get …. data
Preprocessing
Data
Большое количество запросов для получения необходимых данных для страницы
Предварительная подготовка данных для UI
4. SERVICE
Send list of endpointsPreprocessing
Data
domain.com/api/user
domain.com/api/comments
domain.com/api/posts
List of endpoints
Aggregation mechanism
8. Облегчает агрегацию данных из нескольких
источников
Транспорт данных клиент-сервер
(http, WS, etc.)
CLIENT
SERVICE
SERVICE
Request - Response
Request - Response
9. Облегчает агрегацию данных из нескольких
источников
Транспорт данных клиент-сервер
(http, WS, etc.)
CLIENT
SERVICE
SERVICE
15. Передача параметров в запрос
Любое поле в запросе
может принимать параметры
Передача параметров возможно
лишь в весь запрос
domain/v1/user/:id?param=value
18. Query and Mutation
C R U DR
QUERY MUTATION
Для операции «Читать» Для операций «Создать», «Обновить», «Удалить»
19. Variables and Arguments
Декларация переменной.
Задается в JSON формате.
Передаем переменную “key” в качестве
аргумента указывая тип данной
переменной, в данном случаи “String ”.
32. API для сложных выборок
https://facebook.github.io/relay/
https://github.com/facebook/relay
https://www.apollographql.com/
https://github.com/apollographql
35. Вариант 1: products( first:2 offset:2 )
PRODUCT 1
PRODUCT 2
PRODUCT 3
PRODUCT 4
PRODUCT 5
PRODUCT 6
PRODUCT 7
Возвращает
первые два
продукта
PRODUCT 0
PRODUCT 1
PRODUCT 2
PRODUCT 3
PRODUCT 4
PRODUCT 5
PRODUCT 6
PRODUCT 7
Возвращает
следующие
два, не
учитывая
добавленного
Добавлен продукт
36. Вариант 1: products( first:2 offset:2 )
PRODUCT 1
PRODUCT 2
PRODUCT 3
PRODUCT 4
PRODUCT 5
PRODUCT 6
PRODUCT 7
Возвращает
первые два
продукта
PRODUCT 2
PRODUCT 3
PRODUCT 4
PRODUCT 5
PRODUCT 6
PRODUCT 7
Возвращает
следующие
два, не
учитывая
удаленного
Удален Product 1
37. Pagination
Варианты имплементации:
• products( first:2 offset:2 ) – запрашиваются следующие два в списке.
• products( first:2 after:$cursor ) – получаем курсор из последнего элемента и
используем его для разбивки на страницы.
40. Sorting / Filtering
Дополнительный параметр sort у
которого поля:
”field” – поле по которому будет
выполнятся сортировка.
”order”- порядок сортировки.
Фильтрация выполняется
по sku продукта.
42. В каких случаях стоит использовать GraphQL?
• При использовании микросервисной
архитектуры.
• При разработке платформы/сервиса
которая рассчитан на интеграцию с
другими системами/приложениями.
• Если команды размещены в разных
локалях. (сложность коммуникации)
• При разработке простого API.
• При использовании только одного
ресурса предоставления данных.
• При условии что вы разрабатываете
финальный продукт не рассчитанный
на дальнейшее развитие в ближайшем
времени. (Интернет-магазины, промо
сайты, т.д)
43. • GraphQL Voyager - визуально представляет GraphQL API в виде
интерактивного графа.
https://github.com/APIs-guru/graphql-voyager
• GraphCMS - создание, редактирование GraphQL контента.
https://graphcms.com/
• GraphQL Docs – позволяет создать статическую документацию на основе
вашего API.
https://github.com/2fd/graphdoc
• GraphQL Faker – позволяет подменять данные вашего API.
Полезно для тестирования.
https://github.com/APIs-guru/graphql-faker
• Optics – метрики запросов в GraphQL API.
https://www.apollographql.com/engine/
44. Any questions?
The end. Thank You.
Vladimir Zaets
https://github.com/VladimirZaets
https://www.linkedin.com/in/vladimir-zaets-22b2149a/
https://www.facebook.com/vladimir.zaets.75
Editor's Notes
Всем привет, тема которую я хочу представить, это graphql.Как вы уже знаете GraphQL — это стандарт декларирования структуры данных и способов получения данных который выступает дополнительным layer между клиентом и сервером.
Всем привет, тема которую я хочу представить, это graphql.Как вы уже знаете GraphQL — это стандарт декларирования структуры данных и способов получения данных который выступает дополнительным layer между клиентом и сервером.
Всем привет, тема которую я хочу представить, это graphql.Как вы уже знаете GraphQL — это стандарт декларирования структуры данных и способов получения данных который выступает дополнительным layer между клиентом и сервером.
Всем привет, тема которую я хочу представить, это graphql.Как вы уже знаете GraphQL — это стандарт декларирования структуры данных и способов получения данных который выступает дополнительным layer между клиентом и сервером.
Graphql из коробки имеет свой IDE который работает в браузере и называется он GraphiqlОн довольно удобный, сохраняет историю, подствечивает синтаксис, имеет подсказки свойствкоторые мы можем запросить, и так же он умеет парсить документацию описанную в типах, и мы можем читатьее непосредственно при написании запроса.
Graphiql можно включить либо через конфигурациюgraphql с помощу настройки graphiql = true и перейдя по пути имя домена слеш graphql, либо же использоватьодин из екстеншенов для браузера, они имеют немного разный вид но по факту одинаковые.
Давайте более детально разберемся из чего состоит graphql и собственно его синтаксис.
СRUD. Все знают 4 базові функції управління даними, CRUD, создание, чтение, обновлениеи удаление. В случаи реста, который основан на http протоколе, данные возможности реализуютсяс помощу типа запроса, get для чтения, post для создания, put для изменения и delete для удаления соответсвенноgraphql предоставляет всего 2 основных типа запросов, чтение выполняется с помощу типа queryа удаление обновление и создание с помощу типа mutation. При этом query в стучае с http могут использоватьи get и post метод.Основе различие между query и mutation в том что query выполняются паралельно, т.к они не изменяют данных, а мутейшены выполняются последовательно, т.к они изменяют данные, и если бы они выполнялись паралельно то могли б возникать сайд ефекты в виду колизии данных.
graphql query language поддерживает понятие переменных, формат записи переменных это обычныйJSON. В данном случаи мы передаем переменную key в запрос User, явно определя ожидаемыйтип этой переменной. Знак восклицания означает что это обьязательный параметр.далее мы можем использовать данную переменную в любом месте запроса. В данном случаи мы String в данном случаи указывает тип параметра.
Так же мы можем декларировать значения по умолчанию. В данномслучаи 4242.
Алиасы и фрагменты. Допустим в нашем запросе мы хотил получить данныео двух пользователях. В этом случи мы используем алиасы.Мы определяем имя алиаса и непосредственно поле которые мы хотим получить. Результирующиеданные вернутся под ключем с именем алиаса. Так же это довольно юзабельный кейс допустимдаже если нам нужна одна сущность но наш фронтенд для рендеринга ожидает определенный ключ,и что бы не производить пост процессинг, мы можем использовать алиасы.Фрагменты это еще одна довольна удобная фича graphql. Мы можем определить набор полейи переиспользовать их. Если мы вернемся к примеру то мы видим, что мы запрашиваем два юзерано тем не менее поля у них хотим аналогичные и что бы не копипастить поля мы используем фрагмент.Помимо этого мы можем запросить дополнительные поля вместе с фрагментом.
Алиасы и фрагменты. Допустим в нашем запросе мы хотил получить данныео двух пользователях. В этом случи мы используем алиасы.Мы определяем имя алиаса и непосредственно поле которые мы хотим получить. Результирующиеданные вернутся под ключем с именем алиаса. Так же это довольно юзабельный кейс допустимдаже если нам нужна одна сущность но наш фронтенд для рендеринга ожидает определенный ключ,и что бы не производить пост процессинг, мы можем использовать алиасы.Фрагменты это еще одна довольна удобная фича graphql. Мы можем определить набор полейи переиспользовать их. Если мы вернемся к примеру то мы видим, что мы запрашиваем два юзерано тем не менее поля у них хотим аналогичные и что бы не копипастить поля мы используем фрагмент.Помимо этого мы можем запросить дополнительные поля вместе с фрагментом.
Алиасы и фрагменты. Допустим в нашем запросе мы хотил получить данныео двух пользователях. В этом случи мы используем алиасы.Мы определяем имя алиаса и непосредственно поле которые мы хотим получить. Результирующиеданные вернутся под ключем с именем алиаса. Так же это довольно юзабельный кейс допустимдаже если нам нужна одна сущность но наш фронтенд для рендеринга ожидает определенный ключ,и что бы не производить пост процессинг, мы можем использовать алиасы.Фрагменты это еще одна довольна удобная фича graphql. Мы можем определить набор полейи переиспользовать их. Если мы вернемся к примеру то мы видим, что мы запрашиваем два юзерано тем не менее поля у них хотим аналогичные и что бы не копипастить поля мы используем фрагмент.Помимо этого мы можем запросить дополнительные поля вместе с фрагментом.
Алиасы и фрагменты. Допустим в нашем запросе мы хотил получить данныео двух пользователях. В этом случи мы используем алиасы.Мы определяем имя алиаса и непосредственно поле которые мы хотим получить. Результирующиеданные вернутся под ключем с именем алиаса. Так же это довольно юзабельный кейс допустимдаже если нам нужна одна сущность но наш фронтенд для рендеринга ожидает определенный ключ,и что бы не производить пост процессинг, мы можем использовать алиасы.Фрагменты это еще одна довольна удобная фича graphql. Мы можем определить набор полейи переиспользовать их. Если мы вернемся к примеру то мы видим, что мы запрашиваем два юзерано тем не менее поля у них хотим аналогичные и что бы не копипастить поля мы используем фрагмент.Помимо этого мы можем запросить дополнительные поля вместе с фрагментом.
Директивы, из коробки их всего две @include и @skip, они по сути инверсивны, то естьв данном случае если инклуд тру то мы будем получать данные по этому полю, и наоборотесли же скип тру не будет получать данные по полю.Так же есть возможность писать кастомные директивы, в документации я не нашел что бы было сказано об этом, но если посмотреть на реализацию директив то это не сложно и это работает.Я предпологаю что в будущих версиях graphql набор директив из коробки увеличится.
Директивы, из коробки их всего две @include и @skip, они по сути инверсивны, то естьв данном случае если инклуд тру то мы будем получать данные по этому полю, и наоборотесли же скип тру не будет получать данные по полю.Так же есть возможность писать кастомные директивы, в документации я не нашел что бы было сказано об этом, но если посмотреть на реализацию директив то это не сложно и это работает.Я предпологаю что в будущих версиях graphql набор директив из коробки увеличится.
Директивы, из коробки их всего две @include и @skip, они по сути инверсивны, то естьв данном случае если инклуд тру то мы будем получать данные по этому полю, и наоборотесли же скип тру не будет получать данные по полю.Так же есть возможность писать кастомные директивы, в документации я не нашел что бы было сказано об этом, но если посмотреть на реализацию директив то это не сложно и это работает.Я предпологаю что в будущих версиях graphql набор директив из коробки увеличится.
Мы можем создавать интерфесы и имплементировать их в своих типах, это добавляет дополнительную строгостьчто как по мне довольно хорошо. Давайте посмотрим на пример, мы создали интерфейс Character, и создали два типа имплементировав интерфейс Character, тип human также имеет два дополнительныхполя старшипс и тотал кредитс, а дроид поле приймари фанкшн. Теперь допустим мы хотим получить главного героя в эпизоде. Мы обьявили поле hero которое ожидает в качестве параметра эпизод и возвращает данные о главном герое. Главным героем может иметь тип либо human (человек) либо дроид.И допустим мы хотим получить данные о поле праймариФанкшн которое существует у типа дроид но отсутсвует у типа хюман.Просто обьявив это поле в явном виде мы получим ошибку. В данном случаи нам и нужно использовать инлайн фрагменты.По факту это те же фрагменты только обьявлены непосредственно в запросе, и имеют немного другое предназначение.В данном случаи мы говорим что если тип героя Droid тогда возвращаем данные по полю primaryFunction.
Мы можем создавать интерфесы и имплементировать их в своих типах, это добавляет дополнительную строгостьчто как по мне довольно хорошо. Давайте посмотрим на пример, мы создали интерфейс Character, и создали два типа имплементировав интерфейс Character, тип human также имеет два дополнительныхполя старшипс и тотал кредитс, а дроид поле приймари фанкшн. Теперь допустим мы хотим получить главного героя в эпизоде. Мы обьявили поле hero которое ожидает в качестве параметра эпизод и возвращает данные о главном герое. Главным героем может иметь тип либо human (человек) либо дроид.И допустим мы хотим получить данные о поле праймариФанкшн которое существует у типа дроид но отсутсвует у типа хюман.Просто обьявив это поле в явном виде мы получим ошибку. В данном случаи нам и нужно использовать инлайн фрагменты.По факту это те же фрагменты только обьявлены непосредственно в запросе, и имеют немного другое предназначение.В данном случаи мы говорим что если тип героя Droid тогда возвращаем данные по полю primaryFunction.
Мы можем создавать интерфесы и имплементировать их в своих типах, это добавляет дополнительную строгостьчто как по мне довольно хорошо. Давайте посмотрим на пример, мы создали интерфейс Character, и создали два типа имплементировав интерфейс Character, тип human также имеет два дополнительныхполя старшипс и тотал кредитс, а дроид поле приймари фанкшн. Теперь допустим мы хотим получить главного героя в эпизоде. Мы обьявили поле hero которое ожидает в качестве параметра эпизод и возвращает данные о главном герое. Главным героем может иметь тип либо human (человек) либо дроид.И допустим мы хотим получить данные о поле праймариФанкшн которое существует у типа дроид но отсутсвует у типа хюман.Просто обьявив это поле в явном виде мы получим ошибку. В данном случаи нам и нужно использовать инлайн фрагменты.По факту это те же фрагменты только обьявлены непосредственно в запросе, и имеют немного другое предназначение.В данном случаи мы говорим что если тип героя Droid тогда возвращаем данные по полю primaryFunction.
Работа с юнион типами очень похожа на работу с инлайн фрагментами, разница лишь в том что юнион типы не могут иметь общих значени.
С основными проблемами GraphQL вроде как все, давайте теперь разберем имплементацию более сложных выборок.Я добавил на слайд два самых популярных фреймворка для имплементацииGraphQL API, это Relay от фейсбука и apollo. практически всео чем мы будем сейчас с вами говорить уже реализовано в этих фреймворках.
Первый самый явный вариант реализации пагинации это использовать2 аргумента, первый говорит нам сколько айтемов мы хотим получить,и второй это шаг смещения.
Давайте рассмотрим пример. у нас есть список продуктов, такой запрос возвращает первые два элемента, затем еще два и вроде все работает. Но допустим мы получили первый набор данных для первой страниц. После этого добавился еще продукт в начало колекции. В таком случаи следуйщий запрос на получение данных по второй странице вернет уже не валидные данные, а собственно, еще раз вернет второй продукт.
Либо наоборот, кто то удалит первый продукт в списке, в таком случаи наша выборка пропустит третий продукт.
Теперь давайте рассмотрим второй, правильный вариант. Мы так же передаем два аргумента, first который по врежнему отвечает за количество продуктов которые мы хотим получить, и after который говорит нам что следущие айтемы нужно брать после этого значения. Значение в данном случаи это курсор.
Курсор это так называемый идинтифакатор который представленный как base64 строка которая получена на основесвойств обьекта или чаще всего только на одном свойстве-идентификаторе.Мы отправляем запрос, получаем ответ вместе с курсором, который нам нужен для получения следущего набора данных. Чаще всего добавляют еще дополнительнуюинформационые свойства, к примеру nextPage, которое говорит нам есть ли данные для следущей станици или тоталс - на сколько страниц у нас есть данныхи т.д.Собственно такой подход реализации пагинации не спецефичен для graphql это обычная cursor-based пагинация.
Далее давайте поговорим про сортировку и фильтрацию.
Для сортировки в качестве параметра к полю мы используем обьект sort у него есть два свойства это field - поля по которому будет происходить сортировка и ордер которое отвечает за порядок сортировкис фильтрацие все происходит ровно так же, передаем аргументом обьект фильтр, у которого свойство выступает ключем по которому будет происходить фильтация.
Так же давайте рассмотрим более гибкую реализацию фильтация. В данном случаи появляются дополнительные поля OR и AND, в остальном фильтрация выполняется таким же образом.
Теперь давайте разберемся в каких случаях вам стоит использоватьGraphQL а в каких не стоит. И так нужно использовать в случаяхесли у вас микросервисная архитектура, в таком случаи у вас в любом случаи будет какой либо API Gateway, так почему не использовать для этого GraphQLДалее, разработке платформы/сервиса которая рассчитан на интеграцию с другими системами/приложениями.Конечно если интеграция является довольно важным аспектом вашего приложения то очень важно иметь удобный API. По моему мнениюGraphQL действительно очень удобный, и в таких случаях затраты на имплементацию отправданы.И третий случай, если комманды размещены в разных локалях, и имеются сложности в комуникации. GraphQL позволяет максимально разделить серверную и клиенскую часть и это позволяет не создаватьботл неки между командами.
И на последок, ответ на вопрос, является ли GraphQL убийцей REST?Мое мнение нет не является, и у GraphQL и у REST есть свои предназначенияс которыми они отлично справляются. Все плюсы и минусы которые я озвучилявляются обобщенными и субьективными, т.к когда какое API вам использовать зависит от очень большого количества причин и нужно рассматривать конкретный случай.Всем спасибо, и на последнем сайте ссылки на полезные утилиты при разработке GraphQL API