1. Обзор
При создании веб-сервисов для поддержки наших приложений мы можем использовать REST или GraphQL в качестве шаблона для связи. Хотя оба, скорее всего, будут использовать JSON через HTTP, они имеют разные преимущества и недостатки.
В этом руководстве мы сравним GraphQL с REST. Мы создадим пример базы данных продукта и сравним, как два решения различаются при выполнении одних и тех же клиентских операций.
2. Пример услуги
Наш пример сервиса позволит нам:
- Создать продукт в статусе черновик
- Обновите информацию о продукте
- Получить список продуктов
- Получите подробную информацию об одном продукте вместе с его заказами
Начнем с создания приложения с помощью REST.
3. ОТДЫХ
REST (передача репрезентативного состояния) — это архитектурный стиль для распределенных систем гипермедиа. Основной элемент данных в REST называется Resource . В этом примере ресурс — «продукт»
.
3.1. Создать продукт
Чтобы создать продукт, мы будем использовать метод POST
в нашем API:
curl -X POST -H "Content-Type:application/json" -d '
{
"name": "Watch",
"description": "Special Swiss Watch",
"status": "Draft",
"currency": "USD",
"price": null,
"image_url": null,
"video_url": null,
"stock": null,
"average_rating": null
}' https://graphqlvsrest.com/product
В результате система создаст новый продукт.
3.2. Обновить продукт
В REST мы традиционно обновляем продукты с помощью метода PUT
:
curl -X PUT -H "Content-Type:application/json" -d '
{
"name": "Watch",
"description": "Special Swiss Watch",
"status": "Draft",
"currency": "USD",
"price": 1200.0,
"image_url": ["https://graphqlvsrest.com/imageurl/product-id"],
"video_url": ["https://graphqlvsrest.com/videourl/product-id"],
"stock": 10,
"average_rating": 0.0
}'
https://graphqlvsrest.com/product/{product-id}
В результате будет обновлен объект {product-id}
.
3.3. Получить список продуктов
Список продуктов обычно представляет собой операцию GET
, где мы можем использовать строку запроса для указания разбиения на страницы:
curl -X GET https://graphqlvsrest.com/product?size=10&page=0
Первый объект ответа:
{
"id": 1,
"name": "T-Shirt",
"description": "Special beach T-Shirt",
"status": Published,
"currency": "USD",
"price": 30.0,
"image_url": ["https://graphqlvsrest.com/imageurl/1"],
"video_url": ["https://graphqlvsrest.com/videourl/1"],
"stock": 10,
"average_rating": 3.5
}
3.4. Получите единый продукт с заказами
Чтобы получить продукт и его заказ, мы обычно ожидаем получить список продуктов с помощью предыдущего API, а затем сделать вызовы к ресурсу
заказа
, чтобы найти связанные заказы:
curl -X GET https://graphqlvsrest.com/order?product-id=1
Первый объект ответа:
{
"id": 1,
"product_id": 1,
"customer_uuid": "de68a771-2fcc-4e6b-a05d-e30a8dd0d756",
"status": "Delivered",
"address": "43-F 12th Street",
"creation_date": "Mon Jan 17 01:00:18 GST 2022"
}
Поскольку мы запрашиваем заказы по идентификатору продукта
, имеет смысл указать идентификатор в качестве параметра запроса для операции GET .
Однако мы должны отметить, что нам нужно будет выполнить эту операцию один раз для каждого интересующего нас продукта в дополнение к исходной операции для получения всех продуктов. Это связано с проблемой выбора N + 1
.
4. GraphQL
GraphQL — это язык запросов для API, который поставляется со средой выполнения для выполнения этих запросов с использованием существующих служб данных.
Строительные блоки GraphQL — это запросы и мутации . Запрос отвечает за выборку данных, а мутации используются для создания и обновления.
И запрос, и мутация определяют схему . Схема определяет возможные клиентские запросы и ответы.
Давайте повторно реализуем наш пример, используя GraphQL Server .
4.1. Создать продукт
Давайте используем мутацию с именем saveProduct
:
curl -X POST -H "Content-Type:application/json" -d'
{
"query": "mutation {saveProduct (
product: {
name: \"Bed-Side Lamp\",
price: 24.0,
status: \"Draft\",
currency: \"USD\"
}){ id name currency price status}
}"
}'
https://graphqlvsrest.com/graphql
В этой функции saveProduct
все, что находится внутри круглых скобок, является схемой типа ввода . Фигурные скобки после этого описывают поля , которые должны быть возвращены сервером.
Когда мы запускаем мутацию, мы должны ожидать ответа с выбранными полями:
{
"data": {
"saveProduct": {
"id": "12",
"name": "Bed-Side Lamp",
"currency": "USD",
"price": 24.0,
"status": "Draft"
}
}
}
Этот запрос очень похож на запрос POST, который мы сделали с версией REST, хотя теперь мы можем немного настроить ответ.
4.2. Обновить продукт
Точно так же мы можем использовать другую мутацию с именем updateProduct
для изменения продукта:
curl -X POST -H "Content-Type:application/json" -d'
{
"query": "mutation {updateProduct (id:12
product: {
price: 14.0,
status: \"Publish\"
}){ id name currency price, status}
}"
}'
https://graphqlvsrest.com/graphql
Получаем выбранные поля в ответе:
{
"data": {
"updateProduct": {
"id": "12",
"name": "Bed-Side Lamp",
"currency": "USD",
"price": 14.0,
"status": "Published"
}
}
}
Как мы видим, GraphQL обеспечивает гибкость в отношении формата ответов .
4.3. Получить список продуктов
Чтобы получить данные с сервера, мы будем использовать запрос:
curl -X POST -H "Content-Type:application/json" -d
'{
"query": "query {products(size:10,page:0){ id name status}}"
}'
https://graphqlvsrest.com/graphql
Здесь мы также описали страницу результатов, которую хотим видеть:
{
"data": {
"products": [
{
"id": "1",
"name": "T-Shirt",
"status": "Published"
},...
]
}
}
4.4. Получите единый продукт с заказами
С помощью GraphQL мы можем попросить сервер GraphQL объединить продукты и заказы:
curl -X POST -H "Content-Type:application/json" -d
'{
"query": "query {product(id:1){ id name orders{customer_uuid address status creation_date}}}"
}'
https://graphqlvsrest.com/graphql
В этом запросе мы получаем продукт с идентификатором
, равным 1, вместе с его заказами. Это позволяет нам сделать запрос за одну операцию. Давайте проверим ответ:
{
"data": {
"product": {
"id": "1",
"name": "T-Shirt",
"orders": [
{
"customer_uuid": "de68a771-2fcc-4e6b-a05d-e30a8dd0d756",
"status": "Delivered",
"address": "43-F 12th Street",
"creation_date": "Mon Jan 17 01:00:18 GST 2022"
}, ...
]
}
}
}
Как мы видим здесь, ответ содержит информацию о продукте и его соответствующих заказах.
Чтобы добиться этого с помощью REST, нам нужно было отправить пару запросов — первый для получения продукта, а второй — для получения соответствующих заказов.
5. Сравнение
Эти примеры показывают, как использование GraphQL уменьшает объем трафика между клиентом и сервером и позволяет клиенту предоставлять некоторые правила форматирования для ответов.
Стоит отметить, что источнику данных, стоящему за этими API-интерфейсами, возможно, придется выполнять те же операции для изменения или извлечения данных, но богатство интерфейса между клиентом и сервером позволяет клиенту выполнять меньше работы с GraphQL.
Давайте сравним два подхода дальше.
5.1. Гибкий и динамичный
GraphQL позволяет выполнять гибкие и динамические запросы:
- Клиентские приложения могут запрашивать только обязательные поля
- Псевдонимы могут использоваться для запроса полей с пользовательскими ключами.
- Клиент может использовать запрос для управления порядком результатов.
- Клиент может быть лучше отделен от любых изменений в API, поскольку нет единой версии структуры объекта ответа, которой нужно следовать.
5.2. Менее дорогие операции
Каждый запрос к серверу имеет цену за время приема-передачи и размер полезной нагрузки.
В REST мы можем в конечном итоге отправить несколько запросов для достижения требуемой функциональности. Эти множественные запросы будут дорогостоящей операцией. Кроме того, полезная нагрузка ответа может содержать ненужные данные, которые могут не потребоваться клиентскому приложению.
GraphQL старается избегать дорогостоящих операций. Часто мы можем получить все нужные нам данные одним запросом, используя GraphQL .
5.3. Когда использовать REST?
GraphQL не является заменой REST. Оба могут даже сосуществовать в одном приложении. Повышенная сложность размещения конечных точек GraphQL может стоить того, в зависимости от варианта использования.
Мы можем предпочесть REST, когда:
- Наши приложения, естественно, ориентированы на ресурсы, где операции напрямую и полностью связаны с отдельными сущностями ресурсов.
- Необходимо веб-кеширование, поскольку GraphQL изначально его не поддерживает.
- Нам требуется загрузка файлов, поскольку GraphQL изначально не поддерживает это.
6. Заключение
В этой статье мы сравнили REST и GraphQL на практическом примере.
Мы увидели, как можно условно использовать каждый изученный подход.
Затем мы обсудили, почему ни один из подходов не имеет явных преимуществ перед другим. Наши требования будут движущей силой при выборе между ними. Иногда оба могут сосуществовать.
Как всегда, пример кода для этой статьи доступен на GitHub .