Знакомство с GraphQL: примеры запросов к своей БД в облаке Hasura

REST GraphQL примеры курсы обучение, архитектура и интеграция информационных систем GraphQL простыми словами для начинающих примеры курсы обучение, примеры GraphQL курсы обучение, основы архитектуры и интеграции информационных систем для бизнес-аналитика, SQL GraphQL основы введение примеры, краткий ликбез по GraphQL API, обучение системных и бизнес-аналитиков, курсы системного и бизнес-анализа, Школа прикладного бизнес-анализа Учебный Центр Коммерсант

Недавно я упоминала про 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
Ближайшая дата курса
6 февраля, 2023
Длительность обучения
8 ак.часов
Стоимость обучения
15 000 руб.

Реализация проекта в облаке Hasura

Зарегистрировавшись в облачной платформе Hasura и выполнив вход через Github-аккаунт, создадим новый проект на бесплатном плане. В качестве примера рассмотрим сервис заказов интернет-магазина.

graphql api пример для аналитика
Создаем свой проект в Hasura Cloud

Далее создаем свою базу данных: платформа позволяет работать с PostgreSQL как с бессерверным решением, развернутым в Neon. Если бесплатный план (3 базы данных) заполнен, удалить лишнее можно в веб-интерфейсе платформы Neon.

graphql api postgresql пример для аналитика
Создаем бессерверную базу данных PostgreSQL на платформе Neon в Hasura Cloud

Визуализацию схемы данных я сделала в бесплатном веб-редакторе Drawsql, а в GUI облачной платформы Hasura создала таблицы моей базы данных.

SQL для аналитика, схема БД, таблицы БД
Создаем таблицы своей реляционной БД

Наполнив таблицы данными, можно приступить к самому интересному – созданию GraphQL-запросов к своей БД. Для этого платформа Hasura предоставляет визуальные средства: достаточно выбрать тип запроса (простой запрос на чтение, мутация или подписка) и необходимые данные. Сам текст запроса Hasura формирует автоматически. Также в GUI выводится JSON-структура ответа и документация.

GraphQL пример для аналитика
GraphQL-запросы и ответы на них в GUI Hasura Cloud

Например, для добавления нового продукта в соответствующую таблицу я выбрала запрос типа 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-запрос пример
SQL-запрос и план его выполнения

Сгенерированный 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
Ближайшая дата курса
8 февраля, 2023
Длительность обучения
12 ак.часов
Стоимость обучения
20 000 руб.

Подробнее эти и другие темы по основам архитектуры и интеграции информационных систем разбираются на курсах Школы прикладного бизнес-анализа в нашем лицензированном учебном центре обучения и повышения квалификации системных и бизнес-аналитиков в Москве:

 

Я даю свое согласие на обработку персональных данных и соглашаюсь с политикой конфиденциальности.

Добавить комментарий

Поиск по сайту

Напишите нам, мы онлайн!