Недавно я упоминала про GraphQL как стиль интеграции информационных систем по веб-API. Сегодня рассмотрим более детально, как выглядят запросы GraphQL, реализовав практический пример в облаке Hasura с бессерверной базой данных PostgreSQL.
Что такое GraphQL: краткий ликбез
GraphQL — это язык запросов к данным, представленный в 2012 году, чтобы нивелировать недостатки REST API, связанные с передачей избыточных или недостаточных данных от множества конечных точек. Он позволяет через вход в ресурс получать доступ к другим связанным ресурсам, если взаимосвязь между ними заранее определена в схеме данных. Будучи декларативным языком запросов для API со встроенной проверкой типов данных и серверной средой выполнения, GraphQL возвращает сложный граф данных (отсюда и слово Graph в названии), уменьшая количество запросов по сети до одного показа. CRUD-операции над данными в GraphQL реализуются через разные виды POST-запросов:
- простые запросы (query) на чтение данных аналогичны GET в REST API;
- создание новых и изменение существующих данных реализуются через запросы-мутации (mutation), которые позволяют клиенту создавать, обновлять и удалять данные на сервере;
- подписки (subscriptions), которые позволяют клиенту оперативно получать обновления в базе данных, прослушивая изменения в режиме реального времени. Подписки используют вебсокеты, создающие интерактивное соединение между клиентом (браузером) и сервером для обмена сообщениями в реальном времени. Данные передаются в обе стороны (от клиента к серверу и, наоборот, от сервера к клиенту), что актуально для сценариев длительного соединения в реальном времени, например, онлайн-биржа, онлайн-игры и пр.
GraphQL предоставляет следующие преимущества:
- очень гибкий и обеспечивает именно то, что нужно клиенту, избегая передачи излишних данных;
- исключает излишние запросы из-за недостатка данных;
- поддерживается многими языками программирования (JavaScript, Java, Python, Ruby и PHP);
- позволяет настраивать структуру данных;
- один запрос может содержать поля из нескольких ресурсов.
Обратной стороной этих достоинств GraphQL являются сложность реализации, статичная схема данных, отсутствие встроенной поддержки кэширования и трудности в управлении версиями. Запросы могут быть излишне сложными, а также по умолчанию не поддерживается загрузка файлов. Наконец, GraphQL работает только с JSON-структурами данных, тогда как REST воспринимает любые форматы (JSON, XML, HTML, TXT и пр.)
Однако, GraphQL API хорошо подходит для приложений с большим количеством клиентов и/или источников данных, когда нужно реализовать единообразие в средствах выполнения запросов, уменьшить число конечных точек и снизить нагрузку на сеть. Например, всем известные Github и Youtube используют GraphQL. Также благодаря своей гибкой структуре запросов GraphQL отлично подходит для баз с большим количеством записей, позволяя устранить избыточную выборку результатов и получать только нужные данные, чтобы повысить производительность приложения. Кроме того, можно использовать GraphQL, когда нет четкого понимания, как клиент использует API, без необходимости заранее определять строгий контракт: можно постепенно создавать API на основе отзывов клиентов.
Чтобы понять, как это работает, рассмотрим практический пример реализации GraphQL-запросов к объектно-реляционной базе данных PostgreSQL в рамках собственного проекта в облачной платформе Hasura.
Основы архитектуры и интеграции информационных систем
Код курса
OAIS
Ближайшая дата курса
20 января, 2025
Продолжительность
22 ак.часов
Стоимость обучения
48 000 руб.
Реализация проекта в облаке Hasura
Зарегистрировавшись в облачной платформе Hasura и выполнив вход через Github-аккаунт, создадим новый проект на бесплатном плане. В качестве примера рассмотрим сервис заказов интернет-магазина.
Далее создаем свою базу данных: платформа позволяет работать с PostgreSQL как с бессерверным решением, развернутым в Neon. Если бесплатный план (3 базы данных) заполнен, удалить лишнее можно в веб-интерфейсе платформы Neon.
Визуализацию схемы данных я сделала в бесплатном веб-редакторе Drawsql, а в GUI облачной платформы Hasura создала таблицы моей базы данных.
Наполнив таблицы данными, можно приступить к самому интересному – созданию GraphQL-запросов к своей БД. Для этого платформа Hasura предоставляет визуальные средства: достаточно выбрать тип запроса (простой запрос на чтение, мутация или подписка) и необходимые данные. Сам текст запроса Hasura формирует автоматически. Также в GUI выводится JSON-структура ответа и документация.
Например, для добавления нового продукта в соответствующую таблицу я выбрала запрос типа mutation, который назвала AddProduct. При выборе мутации в GUI сразу появляется перечень возможных операций изменения данных в каждой таблице: вставка новой записи (INSERT), изменение (UPDATE) и удаление (DELETE). Мой запрос на добавление нового продукта в таблицу product с заполнением всех ее полей Hasura сформировала следующим образом:
mutation AddProduct { insert_product_one(object: {product_name: "t-short", product_price: "2", product_provider: "D&G", product_id: 19}) { product_provider product_price product_name product_id } }
Ответ в виде JSON-структуры данных:
{ "data": { "insert_product_one": { "product_provider": "D&G", "product_price": 2, "product_name": "t-short", "product_id": 19 } } }
Далее посмотрим, как выглядят аналитические запросы на чтение данных. Для этого я выбрала тип запроса query и отметила соответствующие поля, которые позволят получить статистику по клиентам, сделавшим хотя бы 1 заказ. Предположим, нам нужна полная информация об этих клиентах (имя, емейл, телефон), общее количество заказов и их суммарная стоимость, а также данные заказам с минимальной и максимальной стоимостью, включая даты, когда эти заказы были сделаны. GraphQL-запрос для получения этих данных выглядит следующим образом:
query GetCustomerStat { customer(order_by: {customer_name: asc, orders_aggregate: {sum: {order_sum: asc}}}, where: {orders_aggregate: {count: {predicate: {_gt: 1}}}}) { customer_phone customer_name customer_email orders_aggregate { aggregate { sum { order_sum } count max { order_sum order_datetime } min { order_datetime order_sum } } } } }
Ответ в виде JSON-структуры:
{ "data": { "customer": [ { "customer_phone": "11111111", "customer_name": "Petr", "customer_email": "petr@email.ru", "orders_aggregate": { "aggregate": { "sum": { "order_sum": 37 }, "count": 2, "max": { "order_sum": 34, "order_datetime": "2022-12-05T00:00:00+00:00" }, "min": { "order_datetime": "2022-10-13T00:00:00+00:00", "order_sum": 3 } } } }, { "customer_phone": "123456789", "customer_name": "Anna", "customer_email": "anna@email.ru", "orders_aggregate": { "aggregate": { "sum": { "order_sum": 68 }, "count": 2, "max": { "order_sum": 56, "order_datetime": "2022-11-23T00:00:00+00:00" }, "min": { "order_datetime": "2022-06-12T00:00:00+00:00", "order_sum": 12 } } } } ] } }
Hasura позволяет посмотреть SQL-запрос, в который транслируется GraphQL-запрос, а также план его выполнения.
Сгенерированный SQL-запрос получился довольно объемным и сложным, вручную я бы написала его по-другому:
SELECT coalesce( json_agg( "root" ORDER BY "root.ar.root.orders.order_by.orders_aggregate.sum.order_sum" ASC NULLS LAST, "root.pg.customer_name" ASC NULLS LAST ), '[]' ) AS "root" FROM ( SELECT "_root.ar.root.orders.order_by.orders_aggregate"."sum.order_sum" AS "root.ar.root.orders.order_by.orders_aggregate.sum.order_sum", row_to_json( ( SELECT "_e" FROM ( SELECT "_root.base"."customer_phone" AS "customer_phone", "_root.base"."customer_name" AS "customer_name", "_root.base"."customer_email" AS "customer_email", "_root.ar.root.orders.order_by.orders_aggregate"."orders_aggregate" AS "orders_aggregate" ) AS "_e" ) ) AS "root", "_root.base"."customer_name" AS "root.pg.customer_name" FROM ( SELECT * FROM "public"."customer" WHERE ( EXISTS ( SELECT 1 FROM ( SELECT count(*) AS "order_count" FROM "public"."order" AS "__be_0_order" WHERE ( ( ( ("__be_0_order"."order_customer") = ("public"."customer"."customer_id") ) AND ('true') ) AND ( ('true') AND ('true') ) ) ) AS "__sub" WHERE ( (("__sub"."order_count") > (('1') :: integer)) AND ('true') ) ) ) ) AS "_root.base" LEFT OUTER JOIN LATERAL ( SELECT sum("order_sum") AS "sum.order_sum", json_build_object( 'aggregate', json_build_object( 'sum', json_build_object('order_sum', sum("order_sum")), 'count', COUNT(*), 'max', json_build_object( 'order_sum', max("order_sum"), 'order_datetime', max("order_datetime") ), 'min', json_build_object( 'order_datetime', min("order_datetime"), 'order_sum', min("order_sum") ) ) ) AS "orders_aggregate" FROM ( SELECT "_root.ar.root.orders.order_by.orders_aggregate.base"."order_sum" AS "order_sum", "_root.ar.root.orders.order_by.orders_aggregate.base"."order_datetime" AS "order_datetime" FROM ( SELECT * FROM "public"."order" WHERE ( ("_root.base"."customer_id") = ("order_customer") ) ) AS "_root.ar.root.orders.order_by.orders_aggregate.base" ) AS "_root.ar.root.orders.order_by.orders_aggregate" ) AS "_root.ar.root.orders.order_by.orders_aggregate" ON ('true') ORDER BY "root.ar.root.orders.order_by.orders_aggregate.sum.order_sum" ASC NULLS LAST, "root.pg.customer_name" ASC NULLS LAST ) AS "_root"
GraphQL-движок Hasura избавил от необходимости писать этот и другие SQL-запросы вручную: система сама определяет связи между полями и формирует функции. Таким образом, облачная платформа Hasure Cloud позволяет познакомиться с GraphQL, полностью создав собственный проект со своей базой данных PostgreSQL, чтобы наполнить ее значениями и генерировать запросы к ней. В этом инструменте еще много других полезных и интересных возможностей, включая мониторинг, отчеты, интеграции с внешними системами. Однако, бесплатный план имеет свои ограничения на количество баз данных и проектов приложений. Впрочем, по желанию можно перейти на коммерческий тариф или удалить неиспользуемые проекты.
Разработка ТЗ на информационную систему по ГОСТ и SRS
Код курса
TTIS
Ближайшая дата курса
25 февраля, 2025
Продолжительность
22 ак.часов
Стоимость обучения
48 000 руб.
Подробнее эти и другие темы по основам архитектуры и интеграции информационных систем разбираются на курсах Школы прикладного бизнес-анализа в нашем лицензированном учебном центре обучения и повышения квалификации системных и бизнес-аналитиков в Москве:
- Основы архитектуры и интеграции информационных систем
- Разработка ТЗ на информационную систему по ГОСТ и SRS