Решение проблем кэширования API GraphQL с помощью шлюзов API

GraphQL часто используется в качестве шлюза API для микросервисов, но также может прекрасно сочетаться с существующими решениями для шлюзов API. Например, с помощью Kong, шлюза API и платформы управления микросервисами. В качестве шлюза API Kong имеет множество возможностей, которые можно использовать для улучшения API-интерфейсов GraphQL. Одной из таких возможностей является добавление прокси-кэша к вышестоящим службам, которые вы добавляете в Kong. Но когда дело доходит до кэширования с помощью GraphQL, необходимо учитывать несколько предостережений из-за природы GraphQL. В этом посте мы рассмотрим проблемы кэширования API GraphQL и то, как шлюз API может помочь в этом.

Зачем использовать кэширование API?

Кэширование — важная часть любого API — вы хотите, чтобы ваши пользователи получали максимально возможное время отклика на свои запросы. Конечно, кэширование не является универсальным решением, и существует множество различных стратегий для разных сценариев.

Предположим, что ваш API — это критическое приложение с высокой посещаемостью. Он сильно пострадает от многих пользователей, и вы хотите убедиться, что он может масштабироваться в соответствии со спросом. Кэширование может помочь вам в этом, снизив нагрузку на ваши серверы и повысив производительность всех пользователей, потенциально снизив затраты и предоставив дополнительные функции безопасности. Кэширование с помощью Kong часто применяется на уровне прокси, что означает, что этот прокси будет кэшировать запросы и обслуживать ответ последнего вызова на конечную точку, если она существует в кеше.

API-интерфейсы GraphQL имеют свои проблемы с кэшированием, о которых вам необходимо знать, прежде чем внедрять стратегию кэширования, как вы узнаете в следующем разделе.

Проблемы кэширования с GraphQL

GraphQL становится все более популярным среди компаний. GraphQL лучше всего описывается как язык запросов для API. Он декларативен, что означает, что вы пишете, как должны выглядеть ваши данные, и оставляете детали этого запроса на усмотрение сервера. Это хорошо для нас, потому что делает наш код более читабельным и удобным для сопровождения за счет разделения задач на реализации на стороне клиента и на стороне сервера.

API-интерфейсы GraphQL могут решать такие проблемы, как избыточная и недостаточная выборка (также называемая проблемой N+1). Но, как и в случае с любым API, плохо спроектированный API GraphQL может привести к ужасным проблемам N+1. Пользователи могут контролировать ответ на запрос GraphQL, изменяя запрос, который они отправляют в API GraphQL, и они даже могут вкладывать данные на нескольких уровнях. Хотя, безусловно, есть способы облегчить эту проблему на бэкэнде с помощью дизайна распознавателей или стратегий кэширования, что, если бы был способ сделать ваш GraphQL API невероятно быстрым, не меняя ни одной строки кода?

StepZen добавляет кэширование к запросам и мутациям, которые полагаются на @rest, см. здесь для получения дополнительной информации.

Используя плагин Kong и GraphQL Proxy Cache Advanced, вы можете! Давайте взглянем.

Настройте кэширование для GraphQL с помощью Kong

Когда вы используете Kong в качестве шлюза API, его можно использовать для прокси-запросов к вашим вышестоящим службам, включая API-интерфейсы GraphQL. С корпоративным плагином GraphQL Proxy Caching Advanced вы можете добавить прокси-кэширование в любой GraphQL API. С помощью этого плагина вы можете включить прокси-кэширование в службе GraphQL, маршруте или даже глобально. Давайте попробуем это, добавив сервис GraphQL в Kong, созданный с помощью StepZen.

С помощью StepZen вы можете создавать API-интерфейсы GraphQL декларативно, используя интерфейс командной строки или написав GraphQL SDL (язык определения схемы). Это независимый от языка способ создания GraphQL, поскольку он полностью зависит от GraphQL SDL. Единственное, что вам нужно для начала, — это существующий источник данных, например, база данных (без) SQL или REST API. Затем вы можете сгенерировать схему и преобразователи для этого источника данных с помощью интерфейса командной строки или написать соединения с помощью GraphQL SDL. Затем схему GraphQL можно развернуть в облаке непосредственно с вашего терминала со встроенной аутентификацией.

Создайте API GraphQL с помощью StepZen

Чтобы получить GraphQL с помощью StepZen, вы можете подключить свой источник данных или использовать один из готовых примеров из Github. В этом посте мы возьмем GraphQL API, созданный поверх базы данных MySQL, из примеров. Клонируя этот репозиторий на свой локальный компьютер, вы получите набор файлов конфигурации и .graphql файлов, содержащих схему GraphQL. Чтобы запустить GraphQL API и развернуть его в облаке, вам необходимо использовать интерфейс командной строки StepZen.

Вы можете установить CLI из npm:

npm i -g stepzen

После установки CLI вы можете зарегистрировать учетную запись StepZen, чтобы развернуть GraphQL API на частной защищенной конечной точке. При желании вы можете продолжить без регистрации, но имейте в виду, что развернутая конечная точка GraphQL будет общедоступной. Чтобы запустить и развернуть GraphQL API, вы можете запустить:

stepzen start

Выполнение этой команды вернет развернутую конечную точку в вашем терминале (например, https://public3b47822a17c9dda6.stepzen.net/api/with-mysql/__graphql). Кроме того, он создает адрес localhost, который можно использовать для локального изучения GraphQL API с помощью GraphiQL.

Добавьте сервис GraphQL в Kong

Службу, которую вы создали в предыдущем разделе, теперь можно добавить в шлюз Kong с помощью Kong Manager или Admin API. Давайте воспользуемся Admin API, чтобы добавить наш недавно созданный GraphQL API в Kong, для чего нам нужно всего лишь отправить несколько запросов cURL. Сначала нам нужно добавить сервис, а затем нужно добавить маршрут для этого сервиса.

Вы можете запустить следующую команду, чтобы добавить службу GraphQL и маршрут. В зависимости от настройки вашего шлюза Kong вам может потребоваться добавить в запрос заголовки аутентификации:

curl -i -X POST \
  --url http://localhost:8001/services/ \
  --data 'name=graphql-service' \
  --data 'url=https://public3b47822a17c9dda6.stepzen.net/api/with-mysql/__graphql'

curl -i -X POST \
  --url http://localhost:8001/services/graphql-service/routes \
  --data 'hosts[]=stepzen.net' \

API GraphQL теперь добавлен в качестве вышестоящей службы к шлюзу Kong, что означает, что вы уже можете использовать прокси для него. Но не раньше, чем мы добавим к нему плагин GraphQL Proxy Caching Advanced, что также можно сделать с помощью команды cURL:

​​curl -i -X POST \
  --url http://localhost:8001/services/graphql-service/plugins/ \
  --data 'name=graphql-proxy-cache-advanced' \
  --data 'config.strategy=memory'

Используя Kong в качестве прокси для API GraphQL с добавлением этого плагина, все запросы кэшируются автоматически на уровне запросов. По умолчанию TTL (время жизни) кэша составляет 300 секунд, если вы не перезапишете его (например, 600 секунд), добавив --data' config.cache_ttl=600. В следующем разделе мы исследуем кеш, запрашивая проксированную конечную точку GraphQL.

Запрос API GraphQL

Проксированный API GraphQL будет доступен через Kong на конечной точке вашего шлюза. Когда вы отправляете ему запрос, он ожидает получить значение заголовка с именем хоста GraphQL. Поскольку это запрос к API GraphQL, имейте в виду, что все запросы должны быть POST запросами с заголовком Content-Type: application/json и запросом GraphQL, добавленным в тело.

Чтобы отправить запрос к API GraphQL, вы должны сначала создать запрос GraphQL. Когда вы посещаете конечную точку, где развернут API GraphQL, вы обнаружите интерфейс GraphiQL — интерактивную площадку для изучения API GraphQL. В этом интерфейсе вы можете найти полную схему, включая запросы и, возможно, другие операции, которые принимает GraphQL API.

В этом интерфейсе вы можете отправлять запросы и исследовать результат и схему, как показано выше. Чтобы отправить этот же запрос в проксированный API GraphQL, вы можете использовать следующий cURL:

curl -i -X POST 'http://localhost:8000/' \
--header 'Host: stepzen.net' \
--header 'Content-Type: application/json' \
--data-raw '{"query":"query getCustomerList {\n getCustomerList {\n name\n }\n}","variables":{}}'

Этот cURL вернет как результат ответа, так и заголовки ответа:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Length: 445
Connection: keep-alive
X-Cache-Key: 5abfc9adc50491d0a264f1e289f4ab1a
X-Cache-Status: Miss
StepZen-Trace: 410b35b512a622aeffa2c7dd6189cd15
Vary: Origin
Date: Wed, 22 Jun 2022 14:12:23 GMT
Via: kong/2.8.1.0-enterprise-edition
Alt-Svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000
X-Kong-Upstream-Latency: 256
X-Kong-Proxy-Latency: 39

{
  "data": {
    "getCustomerList": [
      {
        "name": "Lucas Bill"
      },
      {
        "name": "Mandy Jones"
      },
      …
    ]
  }
}

На приведенном выше виден ответ GraphQL API, который представляет собой список поддельных клиентов с той же структурой данных, что и запрос, который мы ему отправили. Кроме того, выводятся заголовки ответа, и вот два заголовка, на которых мы должны сосредоточиться: X-Cache-Status и X-Cache-Key. Первый заголовок покажет, было ли попадание в кэш, а второй показывает ключ кэшированного ответа. Чтобы кэшировать ответ, Kong просматривает конечную точку, на которую вы отправляете запрос, и содержимое тела сообщения, которое включает запрос и возможные параметры запроса. Расширенный подключаемый модуль GraphQL Proxy не кэширует часть ответа, если вы повторно используете части запроса GraphQL в другом запросе.

При первом запросе значение X-Cache-Status всегда будет Miss, так как кешированный ответ недоступен. Однако X-Cache-Key всегда будет иметь значение, поскольку по запросу будет создан кеш. Таким образом, значение для X-Cache-Key будет ключом вновь созданного кэшированного ответа или существующего кэшированного ответа из предыдущего запроса.

Давайте снова сделаем этот запрос и сосредоточимся на значениях этих двух заголовков ответа:

X-Cache-Status: Hit
X-Cache-Key: 5abfc9adc50491d0a264f1e289f4ab1a

Во второй раз, когда мы попали в конечную точку проксируемого GraphQL API, кеш попал, и ключ кеша по-прежнему имеет то же значение, что и для первого запроса. Это означает, что ответ на предыдущий запрос был закэширован и теперь возвращается. Вместо этого кэшированный ответ обслуживался как указанное состояние кэша. Если вы не измените срок жизни кэша по умолчанию, кэшированный ответ остается доступным в течение 300 секунд. Если вы отправите тот же запрос в API-интерфейс GraphQL через прокси после истечения TTL, статус кеша будет Miss.

Вы также можете проверить кэшированный ответ напрямую, отправив запрос непосредственно в расширенный плагин GraphQL Proxy. Чтобы получить кешированный ответ от предыдущего запроса, вы можете использовать следующую конечную точку в Admin API вашего экземпляра Kong. Например:

curl http://localhost:8001/graphql-proxy-cache-advanced/5abfc9adc50491d0a264f1e289f4ab1a

Этот запрос возвращает HTTP 200 OK, если кэшированное значение существует, и HTTP 404 Not Found, если его нет. Используя Kong Admin API, вы можете удалить кешированный ответ по его ключу или даже очистить все кешированные ответы. Дополнительную информацию по этому вопросу см. в разделе Удалить кэшированный объект в документации GraphQL Proxy Cache Advanced.

Заключение

В этом посте вы узнали, как добавить GraphQL API в Kong для создания проксируемой конечной точки GraphQL. Добавив его в Kong, вы не только получите все функции, которые Kong предлагает в качестве прокси-сервиса, но также сможете реализовать кэширование для GraphQL API. Вы можете сделать это, установив GraphQL Proxy Cache Advanced, который доступен для экземпляров Plus и Enterprise. С помощью этого плагина вы можете реализовать прокси-кэширование для API-интерфейсов GraphQL, что позволит вам кэшировать ответ на любой запрос GraphQL.

Follow us on Twitter or join our Discord community to stay updated about our latest developments.