Как создать бессерверный GraphQL API для MySQL, Postgres и Aurora

Первоначально опубликовано на Serverless 2 июля 2019 г.

Для раскрытия простой базы данных через GraphQL API требуется много пользовательского кода и инфраструктуры: правда или нет?

Для тех, кто ответил «правда», мы хотим показать вам, что создавать GraphQL API на самом деле довольно просто, с некоторыми конкретными примерами, иллюстрирующими, почему и как.

(Если вы уже знаете, как легко создавать GraphQL API с помощью Serverless, то и в этой статье вы найдете для себя много интересного).

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

Фреймворк Serverless отлично подходит для API GraphQL: с Serverless вам не нужно беспокоиться о запуске, управлении и масштабировании собственных серверов API в облаке, а также писать скрипты для автоматизации инфраструктуры. Подробнее о Serverless можно узнать здесь. Кроме того, Serverless предоставляет отличные возможности для разработчиков, не зависящие от поставщиков, и мощное сообщество, которое поможет вам в создании приложений GraphQL.

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

В этой статье мы рассмотрим, как построить простой GraphQL API с помощью фреймворка Serverless, Node.js и любого из нескольких решений для баз данных, доступных через Amazon RDS: MySQL, PostgreSQL и MySQL workalike Amazon Aurora.

Следите за этим примером в репозитории на GitHub, и давайте погрузимся в работу!

Построение GraphQL API с бэкендом реляционной БД

В нашем примере проекта мы решили использовать все три базы данных (MySQL, PostgreSQL и Aurora) в одной кодовой базе. Мы знаем, что это излишество даже для производственного приложения, но мы хотели поразить вас тем, насколько веб-масштабно мы строим 😉.

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

Определение схемы GraphQL

Давайте начнем с определения схемы GraphQL API, которую мы хотим создать, что мы сделаем в файле schema.gql в корне нашего проекта, используя синтаксис GraphQL. Если вы не знакомы с этим синтаксисом, посмотрите примеры на этой странице документации по GraphQL.

Для начала мы добавляем в схему первые два элемента: сущность User и сущность Post, определяя их следующим образом, чтобы каждый пользователь мог иметь несколько связанных с ним сущностей Post:

type User {

UUID: String

Имя: String

Посты: [Post]

}

тип Post {

UUID: String

Текст: String

}

Теперь мы можем видеть, как выглядят сущности User и Post. Позже мы убедимся, что эти поля могут храниться непосредственно в наших базах данных.

Далее давайте определим, как пользователи API будут запрашивать эти сущности. Хотя мы могли бы использовать два GraphQL-типа User и Post непосредственно в наших GraphQL-запросах, лучше всего вместо них создать входные типы, чтобы сохранить схему простой. Поэтому мы добавим два таких типа ввода, один для постов и один для пользователей:

input UserInput {

Имя: String

Posts: [PostInput]

}

input PostInput {

Текст: String

}

Теперь давайте определим мутации — операции, которые изменяют данные, хранящиеся в наших базах данных через GraphQL API. Для этого мы создадим тип Mutation. Единственная мутация, которую мы будем использовать сейчас, это createUser. Поскольку мы используем три разные базы данных, мы добавим мутацию для каждого типа базы данных. Каждая из мутаций принимает входные данные UserInput и возвращает сущность User:

Мы также хотим обеспечить возможность запроса пользователей, поэтому мы создаем тип Query с одним запросом для каждого типа базы данных. Каждый запрос принимает строку String, которая является UUID пользователя, возвращая сущность User, содержащую его имя, UUID и коллекцию всех связанных с ним Pos«t:

Наконец, мы определяем схему и указываем на типы Query и Mutation:

schema { query: Query mutation: Mutation }
Войти в полноэкранный режим Выход из полноэкранного режима

Теперь у нас есть полное описание нашего нового API GraphQL! Вы можете посмотреть весь файл здесь.

Определение обработчиков для GraphQL API

Теперь, когда у нас есть описание нашего GraphQL API, мы можем написать код, необходимый для каждого запроса и мутации. Мы начнем с создания файла handler.js в корне проекта, рядом с файлом schema.gql, который мы создали ранее.

Первая задача handler.js — прочитать схему:

Константа typeDefs теперь содержит определения для наших сущностей GraphQL. Далее мы указываем, где будет находиться код наших функций. Чтобы все было понятно, мы создадим отдельный файл для каждого запроса и мутации:

В константе resolvers теперь хранятся определения всех функций нашего API. Наш следующий шаг — создание сервера GraphQL. Помните библиотеку graphql-yoga, которую мы требовали выше? Мы будем использовать эту библиотеку здесь, чтобы легко и быстро создать рабочий GraphQL-сервер:

Наконец, мы экспортируем обработчик GraphQL вместе с обработчиком GraphQL Playground (который позволит нам опробовать наш GraphQL API в веб-браузере):

Итак, мы закончили с файлом handler.js. Следующий этап: написание кода для всех функций, которые обращаются к базам данных.

Написание кода для запросов и мутаций

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

Общие запросы

В папке Common мы заполняем файл mysql.js тем, что нам понадобится для мутации createUser и запроса getUser: запрос init для создания таблиц Users и Posts, если они еще не существуют, и запрос user для возврата данных пользователя при создании и запросе пользователя. Мы будем использовать это и в мутации, и в запросе.

Запрос init создает таблицы Users и Posts следующим образом:

Запрос getUser возвращает пользователя и его сообщения:

Обе эти функции экспортируются; мы можем получить к ним доступ в файле handler.js.

Написание мутации

Пришло время написать код для мутации createUser, которая должна принимать имя нового пользователя, а также список всех постов, принадлежащих ему. Для этого мы создадим файл resolver/Mutation/mysql_createUser.js с единственной экспортируемой функцией func для мутации:

Функция мутации должна выполнять следующие действия по порядку:

  1. Подключиться к базе данных, используя учетные данные в переменных окружения приложения.

  2. Вставить пользователя в базу данных, используя имя пользователя, предоставленное в качестве входных данных для мутации.

  3. Также вставьте все посты, связанные с пользователем, предоставленные в качестве входных данных для мутации.

  4. Вернуть созданные данные пользователя.

Вот как мы выполняем это в коде:

Полный файл, определяющий мутацию, можно посмотреть здесь.

Написание запроса

Запрос getUser имеет структуру, схожую с мутацией, которую мы только что написали, но этот запрос еще проще. Теперь, когда функция getUser находится в пространстве имен Common, нам больше не нужен пользовательский SQL в запросе. Итак, мы создаем файл resolver/Query/mysql_getUser.js следующим образом:

Вы можете увидеть полный запрос в этом файле.

Собираем все вместе в файле serverless.yml

Давайте сделаем шаг назад. В настоящее время у нас есть следующее:

  • Схема GraphQL API.

  • Файл handler.js.

  • Файл для общих запросов к базе данных.

  • Файл для каждой мутации и запроса.

Последний шаг — соединить все это вместе с помощью файла serverless.yml. Мы создаем пустой serverless.yml в корне проекта и начинаем с определения провайдера, региона и времени выполнения. Мы также применяем роль LambdaRole IAM (которую мы определим позже здесь) к нашему проекту:

Затем мы определяем переменные окружения для учетных данных базы данных:

Обратите внимание, что все переменные ссылаются на пользовательский раздел, который идет следом и содержит фактические значения переменных. Обратите внимание, что password — это ужасный пароль для вашей базы данных, и его следует изменить на что-то более надежное (возможно, p@ssw0rd 😃):

Что это за ссылки после Fn::GettAtt, спросите вы? Это ссылки на ресурсы базы данных:

Файл resource/MySqlRDSInstance.yml определяет все атрибуты экземпляра MySQL. Вы можете найти его полное содержание здесь.

Наконец, в файле serverless.yml мы определяем две функции, graphql и playground. Функция graphql будет обрабатывать все запросы API, а конечная точка playground создаст для нас экземпляр GraphQL Playground, который является отличным способом опробовать наш GraphQL API в веб-браузере:

Теперь поддержка MySQL для нашего приложения завершена!

Полное содержимое файла serverless.yml вы можете найти здесь.

Добавление поддержки Aurora и PostgreSQL

Мы уже создали всю структуру, необходимую для поддержки других баз данных в этом проекте. Чтобы добавить поддержку Aurora и Postgres, нам нужно только определить код для их мутаций и запросов, что мы и сделаем следующим образом:

  1. Добавьте файл Common queries для Aurora и для Postgres.

  2. Добавьте мутацию createUser для обеих баз данных.

  3. Добавьте запрос getUser для обеих баз данных.

  4. Добавьте конфигурацию в файл serverless.yml для всех переменных окружения и ресурсов, необходимых для обеих баз данных.

На данный момент у нас есть все необходимое для развертывания нашего GraphQL API, работающего на базе MySQL, Aurora и PostgreSQL.

Развертывание и тестирование GraphQL API

Развертывание нашего GraphQL API очень простое.

  • Сначала мы запускаем npm install, чтобы установить наши зависимости.

  • Затем мы запускаем команду npm run deploy, которая устанавливает все переменные окружения и выполняет развертывание.

  • Под капотом эта команда запускает serverless deploy, используя нужное окружение.

Вот и все! На выходе шага deploy мы увидим конечную точку URL для нашего развернутого приложения. Мы можем отправлять POST-запросы к нашему GraphQL API, используя этот URL, а наш Playground (с которым мы поиграем через секунду) доступен с помощью GET по тому же URL.

Пробуем API в GraphQL Playground

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

Давайте создадим пользователя, выполнив следующую мутацию:

mutation { mysql_createUser( input: { Name: "Cicero" Posts: [ { Text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit." } { Text: "Proin consequat mauris orci, ut consequat purus efficitur vel." } ] } ) { Name UUID } }
Войти в полноэкранный режим Выход из полноэкранного режима

В этой мутации мы вызываем API mysql_createUser, предоставляем текст сообщений нового пользователя и указываем, что хотим получить в ответ имя пользователя и UUID.

Вставьте приведенный выше текст в левую часть Playground и нажмите кнопку Play. Справа вы увидите результат запроса:

Теперь давайте сделаем запрос для этого пользователя:

query { mysql_getUser(uuid: "f5593682-6bf1-466a-967d-98c7e9da844b") { Name UUID } }
Войти в полноэкранный режим Выйти из полноэкранного режима

Это вернет нам имя и UUID пользователя, которого мы только что создали. Отлично!

Мы можем сделать то же самое с другими бэкендами, PostgreSQL и Aurora. Для этого нам просто нужно заменить имена мутации на postgres_createUser или aurora_createUser, а запросы на postgres_getUser или aurora_getUser. Попробуйте сами! (Имейте в виду, что пользователи не синхронизируются между базами данных, поэтому вы сможете запрашивать только тех пользователей, которых вы создали в каждой конкретной базе данных).

Сравнение реализаций MySQL, PostgreSQL и Aurora

Начнем с того, что мутации и запросы выглядят одинаково в Aurora и MySQL, поскольку Aurora совместима с MySQL. И есть только минимальные различия в коде между ними и реализацией Postgres.

На самом деле, для простых случаев использования, самое большое различие между нашими тремя базами данных заключается в том, что Aurora доступна только в виде кластера. Самая маленькая доступная конфигурация Aurora все еще включает одну реплику только для чтения и одну реплику для записи, поэтому нам нужна кластерная конфигурация даже для этого базового развертывания Aurora.

Aurora обеспечивает более высокую производительность, чем MySQL и PostgreSQL, в основном благодаря оптимизации SSD, которую Amazon внесла в механизм базы данных. По мере роста вашего проекта вы, вероятно, обнаружите, что Aurora предлагает улучшенную масштабируемость базы данных, более простое обслуживание и более высокую надежность по сравнению с конфигурациями MySQL и PostgreSQL по умолчанию. Но вы можете добиться некоторых из этих улучшений и на MySQL и PostgreSQL, если настроите свои базы данных и добавите репликацию.

Для тестовых проектов и игровых площадок мы рекомендуем MySQL или PostgreSQL. Они могут работать на экземплярах db.t2.micro RDS, которые входят в бесплатный уровень AWS. Aurora в настоящее время не предлагает инстансы db.t2.micro, поэтому вы заплатите немного больше, чтобы использовать Aurora для этого тестового проекта.

Последнее важное замечание

Не забудьте удалить развертывание Serverless после завершения тестирования GraphQL API, чтобы не платить за ресурсы базы данных, которые вы больше не используете.

Вы можете удалить стек, созданный в этом примере, выполнив npm run remove в корне проекта.

Удачных экспериментов!

Резюме

В этой статье мы провели вас через создание простого GraphQL API, используя три различные базы данных одновременно; хотя это не то, что вы когда-либо будете делать в реальности, это позволило нам сравнить простые реализации баз данных Aurora, MySQL и PostgreSQL. Мы увидели, что в нашем простом примере реализация всех трех баз данных примерно одинакова, за исключением небольших различий в синтаксисе и конфигурациях развертывания.

Вы можете найти полный пример проекта, который мы использовали, в этом репозитории GitHub. Самый простой способ поэкспериментировать с проектом — клонировать репозиторий и развернуть его со своей машины с помощью npm run deploy.

Другие примеры GraphQL API с использованием Serverless можно найти в репозитории serverless-graphql.

Если вы хотите узнать больше о масштабировании GraphQL API с помощью Serverless, вам может понравиться наш цикл статей «Запуск масштабируемой и надежной конечной точки GraphQL с помощью Serverless».

Может быть, GraphQL просто не ваш конек, и вы предпочитаете развертывать REST API? Мы поможем вам: ознакомьтесь с некоторыми примерами в этом блоге.

Есть вопросы? Прокомментируйте это сообщение или создайте обсуждение на нашем форуме.

Первоначально опубликовано на https://www.serverless.com.

Оставьте комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *