Переход от REST API к GraphQL на примере реальных проектов
Антон Морев
ДОКУМЕНТАЦИЯ
Инструменты для документации (swagger и тд)
РАЗГРАНИЧЕНИЕ ДАННЫХ
СВОЯ МОДЕЛЬ НА КАЖДУЮ СИТУАЦИЮ
Интернет-магазин Решения на REST
Интернет-магазин Желаемое решение
РЕАЛИЗАЦИЯ НА GRAPHQL
Процесс внедрения нового свойства в сущность товара
Внедрение GraphQL Интернет-магазин
ВНЕДРЕНИЕ GRAPHQL РАЗРАБОТКА С МИКРОСЕРВИСАМИ
ВНЕДРЕНИЕ GRAPHQL ОПТИМИЗАЦИЯ РАЗРАБОТКИ
ОБНОВЛЕНИЕ ДАННЫХ ЧЕРЕЗ GRAPHQL
ОСОБЕННОСТИ GRAPHQL
ТЕСТОВЫЙ КЕЙС
Антон Морев
4.82M

Переход от REST API к GraphQL на примере реальных проектов

1. Переход от REST API к GraphQL на примере реальных проектов

Антон Морев, Wormsoft

2. Антон Морев

Приложения
Сайты
Системы автоматизации (CRM, ERP)
Маркетинг
Сопровождение проектов
IT-Директор
Оптимизация процессов разработки
Review ключевых проектов

3.

Взаимодействие с сервером
DATABASE
CACHE
OTHER API
API
КЛИЕНТ
СЕРВЕР
QUEUE
… ETC

4.

Стандартное решение на REST
GET /goods
POST /order

5. ДОКУМЕНТАЦИЯ

6.

№1
БЕЛЫЙ ЛИСТ
“Я не хочу писать
документацию,
я хочу писать код”
© “Senior” Developer

7.

№2
МУДРЕЦ
в каком поле у нас
текущий статус?
спроси у Ивана - он
знает где у нас это

8.

№3
WORD, 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.

Docs
Docs
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 /list
GET /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.

Обычный запрос в REST
API
Запрос
Парсинг
запроса
Получение
результата
Определение
контроллера
Запуск
контроллера
Ответ

58.

Как работать с GraphQL. Асинхронность
Ответ
Запрос
API
Парсинг запроса
Определение резолверов
Запуск резолвера
Запуск резолвера

Подготовка ответа
Запуск резолвера

59.

За чем следить в GraphQL?
N+1
Сложность
запросов
Сложность
контроля
Кэширование
Асинхронность
Порог
вхождения

60.

Особенности GraphQL. N+1
query {
task {
list {
id
title
}
}
}

61.

Особенности GraphQL. N+1
query {
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
English     Русский Правила