Similar presentations:
Переход от REST API к GraphQL на примере реальных проектов
1. Переход от REST API к GraphQL на примере реальных проектов
Антон Морев, Wormsoft2. Антон Морев
ПриложенияСайты
Системы автоматизации (CRM, ERP)
Маркетинг
Сопровождение проектов
IT-Директор
Оптимизация процессов разработки
Review ключевых проектов
3.
Взаимодействие с серверомDATABASE
CACHE
OTHER API
API
КЛИЕНТ
СЕРВЕР
QUEUE
… ETC
4.
Стандартное решение на RESTGET /goods
POST /order
5. ДОКУМЕНТАЦИЯ
6.
№1БЕЛЫЙ ЛИСТ
“Я не хочу писать
документацию,
я хочу писать код”
© “Senior” Developer
7.
№2МУДРЕЦ
в каком поле у нас
текущий статус?
спроси у Ивана - он
знает где у нас это
8.
№3WORD, EXСEL ,
GOOGLEDOC
«Мы храним документацию
в docx файлах под git
со всеми JSON ответами и
запросами»
9. Инструменты для документации (swagger и тд)
№4Инструменты для документации
(swagger и тд)
10. РАЗГРАНИЧЕНИЕ ДАННЫХ
11.
Количество запросовHEADER
getHeaderData
PRODUCT CARD
getFooterData
getProductCardData
REVIEWS
CONNECTED
PRODUCTS
FOOTER
getReviewsData
getDeliveryData
12.
КАТАЛОГТОВАРОВ
КОРЗИНА
ТОВАР
ИСТОРИЯ
ЗАКАЗОВ
ОТЗЫВЫ
КАРТОЧКА
ТОВАРА
13.
GET /allRoundProduct?id=123{
"connectedProducts": [],
"id": 123,
"photos": [],
"title": "Bentley For Men",
"countInBasket": 3,
"price": 100,
"reviews": [],
"description": "Лучшие духи",
"brand": "Bentley",
"variants": []
}
14. СВОЯ МОДЕЛЬ НА КАЖДУЮ СИТУАЦИЮ
15.
{"id": 123,
"title": "",
"price": "",
GET /product/card?id=123
"description": "",
"brand": "",
"photos": []
}
16.
[{
"id": 123,
"title": "",
GET /product/connected?id=123
"price": 100,
"photo": {}
}
]
17.
[{
"id": 123,
"title": "",
GET /product/list
"photo": [],
"rating": 3,
"price": 100
}
]
18.
ИЕРАРХИЧЕСКАЯМОДЕЛЬ
{
"commonInfo": {},
"cardInfo": {},
GET /product/full?id=123
"listInfo": {},
"basketInfo": {}
}
19. Интернет-магазин Решения на REST
Интернет-магазинРешения
на на
REST
Интернет-магазин.
Решения
REST
product/full?id=1&fields=cardInfo,basketInfo
ЯЗЫК ЗАПРОСОВ
API
только cardInfo и basketInfo
20.
getModel?id=1&fields=title,description,price
getModel?id=1&fields=title,price,
connectedProducts.title,
connectedProducts.description
getModel?id=1&fields= title,description,
rating,price, reviews.user.name,reviews.
user.id,reviews.date,reviews.text,
photos.src,photos.alt,
connectedProducts.title,
connectedProducts.price,
connectedProducts.rating,
dicsount.rate,discount.amount
21.
Интернет-магазин. Решения на RESTМНОГО
ЗАПРОСОВ
(удобно)
ОДИН
ЗАПРОС
(неудобно)
22. Интернет-магазин Желаемое решение
Интернет-магазинИнтернет
магазин. Желаемое
Желаемоерешение
решение
Автоматическая
документация
Можно выбирать что
именно мы хотим
получить
Несколько сущностей
в одном запросе
23. РЕАЛИЗАЦИЯ НА GRAPHQL
24.
ОПИСАНИЕСХЕМЫ
type Product {
id: ID!
title: String
description: String
}
type Query {
product (id: ID!): Product
}
25.
ЗАПРОС25
query {
product (id: 123)
title
description
}
}
{
26.
{"product": {
"title": "Духи",
"description":"Описание товара…"
}
ОТВЕТ
}
27.
ВАРИАНТЫТОВАРА
type Product {
id: ID
title: String
description: String
variants: [ProductVariant]
}
28.
ПОЛУЧЕНИЯПОЛЯ VARIANTS
query {
product (id: 123) {
title
variants {
id
title
}
}
}
29.
{"title": "Chanel Chance Eau Tendre",
"variants": [
{
"id": 1,
"title": "Подарок, 200мл"
},
{
"id": 2,
"title": "Пробник, 1.5мл "
}
]
ОТВЕТ
}
30.
type ProductVariant {ИНТЕРНЕТ-МАГАЗИН
РЕШЕНИЯ НА
GRAPHQL
id: ID
title: String
price: Float
priceDiscount: Float
image: ImageModel
}
31.
ЗАПРОС ДЛЯСТРАНИЦЫ
query {
header {
#header fields
}
product (id: 123) {
#product fields
}
footer {
#footer fields
}
}
32.
33.
Процесс внедрения нового свойствав сущность товара
Выбор/Создание запроса
BACKEND
ДО
Добавление нужного
поля в response
Расширение документации
Реализация логики
получения поля
34. Процесс внедрения нового свойства в сущность товара
Процессвнедрения
нового
свойства
в сущность товара
Выбор/Создание запроса
BACKEND
ПОСЛЕ
Добавление нужного
поля в тип
Расширение документации
Реализация логики
получения поля
35. Внедрение GraphQL Интернет-магазин
Процессвнедрения
нового свойства
в сущность товара
Выяснение в каком запросе
было обновление
FRONTEND
ДО
Изучение документации
Новый endpoint/расширение
старого
Использование поля
36.
Процесс внедрения нового свойствав сущность товара
Добавление нужного поля в
GQL запрос за сущностью
FRONTEND
ПОСЛЕ
Изучение документации
Новый endpoint/расширение
старого
Использование поля
37. ВНЕДРЕНИЕ GRAPHQL РАЗРАБОТКА С МИКРОСЕРВИСАМИ
38.
Банк криптовалютыЯДРО СИСТЕМЫ
Интерфейс
WALLET RPC
КРИПТОВАЛЮТНЫЕ
БИРЖИ
39.
ИНТЕРФЕЙСREST
PHP Yii2
API Module
Email module
Wallet RPC (C++)
Payments module
Deposit module
Auth module
Exchange API
40.
class TransactionsController extends Controller{
public function actionIndex($page = 1, $type = null)
{
$userId = Yii::$app->user->id;
return $this->transactionsRepository
->getTransactions($userId, $page, $type);
}
}
41.
DocsDocs
Email service
(GoLang)
Money module
(PHP)
Docs
Интерфейс
API Core Server
(PHP Yii2)
Docs
Exchanges Services
(PHP, NodeJS)
Chat service
(NodeJS)
42.
'resolve' => function($value, $args, $context, ResolveInfo $info) {//Получение любой информации
}
ПРЯМОЙ ЗАПРОС В БД
'resolve' => function($value, $args, $context, ResolveInfo $info) {
return DB::getInstance()->select('SELECT * from products');
},
СОБСТВЕННЫЙ РЕПОЗИТОРИЙ
'resolve' => function($value, $args, $context, ResolveInfo $info) {
return $context->productRepository->getProducts($args['page']);
}
43.
query {user {
payments {
GET /user/payments/list
list {
id
amount
}
}
}
}
44.
GET /user/payments /listGET /user /info
GET /user /system /status
GET /user /notifications /list
query {
user {
payments {
list {
id
amount
}
}
info {
name
money
}
system {
status
}
notifications {
list {
id
text
}
}
}
}
45. ВНЕДРЕНИЕ GRAPHQL ОПТИМИЗАЦИЯ РАЗРАБОТКИ
46.
Внедрение GraphQL. Админ-панельAPI Server
SITE
сбор данных с API
сервера
отображение данных
Frontend логика
сущности
бизнес логика
обработка заявок
система оповещений
Admin Panel
управление
примитивными
CRUD сущностями
управления бизнес
логикой (формы)
47.
Внедрение GraphQL. Админ-панельОписание
сущности
автоформирование
GraphQL схема
resolvers для
каждого поля
каждой сущности
интерфейс админпанели
48.
{“type”: “input_text”,
“label”: “Название”
“name”: “title”
}
metro {
list {
items {
title
}
}
}
49.
query {offices {
title
photoSrc
address
metro {
list {
title
}
}
shortDescription
price {
month
}
}
}
50.
Изменение в процессе добавления/изменения примитивной сущности
BACKEND
ДО
ПОСЛЕ
Разработка
Логики хранения
данных
Разработка
логики
CRUD
Разработка
интерфейса
управления
Добавление/
расширение
запроса
Обновление
документаци
и API
Обновление
конфигурации
Разработка
логики
CRUD
Разработка
интерфейса
управления
Добавление/
расширение
запроса
Обновление
документаци
и API
51.
Изменение в процессе добавления/изменения примитивной сущности
FRONTEND
ДО
Изучение
документации
Добавление нового
запроса
Обработка данных
ПОСЛЕ
Изучение
документации
Расширение Query
Обработка данных
52. ОБНОВЛЕНИЕ ДАННЫХ ЧЕРЕЗ GRAPHQL
53.
GraphQL. Мутацииmutation {
office {
update (id:123, model: {title: "newTitle"})
}
}
54.
GraphQL. Обновление данных{
taskModule {
task (id: 123) {
mainInfo (
title: “title”,
description: “description”
)
}
}
POST /taskModule/task/mainInfo?id=123
{
title: “title”,
description: “description”
}
}
55.
56. ОСОБЕННОСТИ GRAPHQL
57.
Обычный запрос в RESTAPI
Запрос
Парсинг
запроса
Получение
результата
Определение
контроллера
Запуск
контроллера
Ответ
58.
Как работать с GraphQL. АсинхронностьОтвет
Запрос
API
Парсинг запроса
Определение резолверов
Запуск резолвера
Запуск резолвера
…
Подготовка ответа
Запуск резолвера
59.
За чем следить в GraphQL?N+1
Сложность
запросов
Сложность
контроля
Кэширование
Асинхронность
Порог
вхождения
60.
Особенности GraphQL. N+1query {
task {
list {
id
title
}
}
}
61.
Особенности GraphQL. N+1query {
task {
list {
id
title
subtask {
title
}
}
}
}
62.
Особенности GraphQL. N+1'resolve' => function ($root) {
Loader::add($root->id);
return new Deferred(
function () use ($root) {
Loader::prepareData();
return Loader::get($root->id);
}
);
},
]
63.
Как работать с GraphQL. Сложностьзапроса
task {
subTask {
subTask {
subTask {
subTask {
id
}
}
}
}
}
64.
ОГРАНИЧЕНИЕГЛУБИНЫ ЗАПРОСА
Query Depth < 4
1. task {
2. subTask {
3. subTask {
4. subTask {
5. subTask {
6. id
}
}
}
}
}
65.
1. task {3*i subTask {
3*i subTask {
3*i subTask {
3*i subTask {
3*i id
}
}
}
}
}
2
ОГРАНИЧЕНИЕ
СЛОЖНОСТИ ЗАПРОСА
3
4
5
6
Query Complexity < 40
66.
Как работать с GraphQL. КэшированиеКэширование на уровне web-сервера
GET /api/info
cache
КЛИЕНТ
Приложение
67.
Как работать с GraphQL. КэшированиеКэширование на уровне web-сервера
POST /graphql
КЛИЕНТ
Приложение
Кешировать на основании body
68.
Как работать с GraphQL. КэшированиеКэширование на уровне web-сервера
GET /api/info
cache
Клиент
public function actionInfo()
Приложение
{
$query = ''; //фиксированный запрос
return GraphQLHandler::handleQuery($query);
}
69.
Внедрение GraphQL. Сложностьадаптации
Зачем GraphQL,
если и так сойдет?
70.
Внедрение GraphQL. Сложностьадаптации
А почему не
GraphQL?
71.
Как работать с GraphQL. АсинхронностьЗапрос
Ответ
API
Парсинг запроса
Определение резолверов
1
Запуск резолвера
22
Запуск резолвера
Подготовка ответа
…
N
Запуск резолвера
72.
Как работать с GraphQL. АсинхронностьREST
GET user/info
GET account/money
API
GET something/more
73.
Как работать с GraphQL. АсинхронностьИнициализация запроса ~ от 30мс (PHP)
74.
Как работать с GraphQL. Долгие поля75.
Внедрение GraphQL. Постановкавопроса
Один тяжелый или много легких?
76. ТЕСТОВЫЙ КЕЙС
77.
Нагрузочный тест. Инструментарий78.
Нагрузочный тестSQLITE
API
Nuxt.JS
PHP-SLIM
79.
Нагрузочный тестRedis
API
Node.JS
PHP-SLIM
80.
Нагрузочный тест. ИнструментарийОЗУ: 1ГБ
SSD: 30ГБ
CPU: 1
Backend
Frontend
PHP 7.2
Slim Framework
webonyx/graphql-php
Node.JS 10.16
Express
Axios HTTP Client
81.
Нагрузочный тест. Условия• 30 одновременных пользователей
• Суммарное количество запросов: 200 каждый
82.
Кейс 1. Список товаровТовар 1
Товар 2
Товар 3
…
Товар N
• Сравнение
получение
одинакового
количества
данных
• Проверка влияния
N+1 на результат
83.
Кейс 1. Список товаровСреднее время ответа (мс)
Количество
товаров
REST
GraphQL
без оптимизации
GraphQL с
оптимизацией
5
102
109
104
15
108
180
108
30
120
230
116
50
117
320
130
100
140
500
134
84.
Кейс 2. Карточка товара без связейФото
товара
Описание
товара
Характеристики товара
85.
Кейс 2. Карточка товара без связейСреднее время ответа (мс)
# Теста
REST
GraphQL
1
80
100
2
83
110
3
76
115
4
90
118
5
80
130
86.
Кейс 3. Карточка со связямиФото
товара
Описание
товара
Характеристики товара
Рейтинг
пользователя
Отзывы о товаре
Связанные товары
Рейтинг
товара
Наличие в
корзине
87.
Кейс 3. Карточка со связямиСреднее время ответа (мс)
Количество
связанных
товаров
REST
GraphQL
без оптимизации
GraphQL с
оптимизацией
5
220
300
150
15
240
420
148
30
232
510
145
50
273
604
155
100
310
1 100
180
88.
Небольшой выводСтоит ли подключать GraphQL в
реальные проекты?
Да, но всегда
помнить о:
N+1
Сложностях кеширования
N+1
Сложности запроса
N+1
89.
Как работать с GraphQL. ИнструментыGraphiQL
от создателей
GraphQL
JS-GraphQL
Интерфейс
Работа с подписками
curl export
CPU 20%
интеграция с
кодом проекта
90.
Как работать с GraphQL. БиблиотекиFrontend
Backend
graphql-go/graphql
vuejs/vue-apollo
webonyx/graphql-php
apollographql/react-apollo
graphql/graphql-js
91.
Когда GraphQL усложняет процессы1
2
3
4
В некоторых
MVP
В системах
отчетности и
аналитики
В общих
сервисах
аутентификации
В командах где
не знают
GraphQL
92. Антон Морев
Благодарю за внимание!wormsoft.ru
@amorev
amorev