Первоначально опубликовано на Serverless
В этом прохождении мы создадим бессерверный сервис products-api, который будет реализовывать REST API для продуктов. В качестве языка мы будем использовать Java. Данные будут храниться в таблице DynamoDB, а сервис будет развернут на AWS.
Что мы рассмотрим:
-
Предварительные условия
-
Создание службы REST API
-
Глубокое погружение в код Java
-
Развертывание сервиса
-
Вызов API
Предварительные условия установки
Прежде чем мы начнем, вам понадобится следующее:
-
Установить node и npm
-
Установить Serverless Framework, установленный с настроенной учетной записью AWS.
-
Установите Oracle JDK и NOT Java JRE. Установите следующее: export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk-10.jdk/Contents/Home
-
Установите Apache Maven. После загрузки и установки Apache Maven добавьте папку apache-maven-x.x.x.x в переменную окружения PATH.
Предварительные условия для тестирования
Протестируйте установку Java:
Тестовая установка Maven:
Создайте проект Serverless
Давайте создадим проект с именем products-api, используя шаблон aws-java-maven, предоставленный Serverless Framework, как показано ниже:
Обновление проекта
Бессерверный шаблон aws-java-maven дает нам хорошую отправную точку и создает полностью функциональный сервис, используя Java и Maven. Однако нам нужно будет адаптировать его к создаваемому нами сервису Products API.
Давайте обновим проект hello до products-api в POM, т.е. pom.xml:
serverless.yml
Добавим соответствующие обработчики Lambda в разделе functions и обновим артефакт развертывания в разделе package в соответствии с требованиями нашего проекта.
Обновите следующие разделы:
Управление таблицей DynamoDB
Поскольку мы будем использовать таблицу DynamoDB для хранения данных о наших продуктах, мы позволим Serverless Framework управлять ресурсом DynamoDB и соответствующими разрешениями IAM Role для функций лямбда для доступа к таблице DynamoDB.
Добавьте следующий раздел для iamRoleStatements в раздел provider в файле serverless.yml:
Теперь, чтобы создать и управлять таблицей DynamoDB из нашего бессерверного проекта, мы можем добавить раздел resources в наш файл serverless.yml. Этот раздел описывает ресурс DynamoDB с помощью синтаксиса CloudFormation:
Адаптер DynamoDB
Мы создадим адаптер, в обязанности которого будет входить управление подключением к указанной таблице DynamoDB с помощью конфигурации, например, региона AWS, где будет развернута таблица. Класс адаптера DynamoDB представляет собой синглтон, который инстанцирует клиента AmazonDynamoDB и класс AWS DBMapper.
Вот выдержка из класса DynamoDBAdapter:
Product POJO
У нас есть Product POJO, который представляет сущность Product и инкапсулирует всю ее функциональность в класс. Класс Product POJO определяет структуру данных, которая соответствует схеме таблицы DynamoDB, и предоставляет вспомогательные методы для простого управления данными о продукте.
AWS SDK предоставляет простой способ аннотировать POJO атрибутами, специфичными для DynamoDB, как определено в Java Annotations for DynamoDB.
Мы аннотируем класс Product POJO с:
-
атрибутом DynamoDBTable для указания имени таблицы DynamoDB
-
атрибут DynamoDBHashKey для сопоставления свойства с ключом DynamoDB Haskey
-
атрибут DynamoDBRangeKey для сопоставления свойства с ключом диапазона DynamoDB RangeKey
-
атрибут DynamoDBAutoGeneratedKey для отображения свойства, которому необходимо получить автоматически генерируемый идентификатор.
Также обратите внимание, что мы получаем имя таблицы продуктов из переменной среды PRODUCTS_TABLE_NAME, определенной в нашем файле serverless.yml:
Далее рассмотрим методы, которые использует Product POJO для управления данными.
Метод конструктора
Публичный конструктор делает несколько вещей:
-
Переопределяет значение аннотации имени таблицы PLACEHOLDER_PRODUCTS_TABLE_NAME фактическим значением из переменной окружения.
-
Получает экземпляр DynamoDBAdapter
-
Получает экземпляр клиента AmazonDynamoDB
-
Получает экземпляр DynamoDBMapper
Метод list()
Метод list() использует конструкцию DynamoDBScanExpression для получения всех продуктов из таблицы products. Он возвращает список продуктов через структуру данных List. Он также регистрирует полученный список продуктов.
Метод get()
Метод get() принимает идентификатор продукта и использует DynamoDBQueryExpression для установки выражения запроса для соответствия переданному идентификатору продукта. Объект mapper имеет метод запроса, которому передается queryExp, чтобы получить соответствующий продукт:
Метод save()
Метод save() принимает экземпляр продукта, заполненный значениями, и передает его в метод save объекта mapper, чтобы сохранить продукт в базовой таблице:
Метод delete()
Метод delete() принимает идентификатор продукта и затем вызывает метод get(), чтобы сначала проверить, существует ли продукт с соответствующим идентификатором. Если он существует, то вызывается метод delete объекта mapper, чтобы удалить продукт из базовой таблицы:
Примечание: POJO-класс Product может быть протестирован независимо, чтобы убедиться, что функциональность управления данными работает с таблицей DynamoDB. Такое разделение позволяет нам написать модульные тесты для тестирования основной функциональности DAL.
Реализация API
Теперь, когда наш Product DAL написан и работает так, как ожидалось, мы можем приступить к рассмотрению обработчиков функций API, которые будут вызывать Product DAL для обеспечения ожидаемой функциональности.
Мы определим конечные точки API, затем сопоставим события с обработчиками и, наконец, напишем код обработчика.
Конечные точки API
Прежде чем мы рассмотрим обработчики API, давайте взглянем на конечные точки API, которые мы сопоставим с обработчиками.
Конечные точки API будут выглядеть следующим образом:
POST /products: Создать продукт и сохранить его в таблице DynamoDB.
GET /products/: Получает все существующие продукты.
GET /products/{id}: Получает существующий продукт по id.
DELETE /products/{id}: Удаляет существующий продукт по id.
Сопоставление событий с обработчиками
Для реализации конечных точек API, которые мы описали выше, нам нужно добавить события, которые сопоставляют наши конечные точки API с соответствующими обработчиками функций лямбда.
Обновите следующие разделы в файле serverless.yml:
Написание обработчиков
Давайте напишем код для четырех обработчиков, которые предоставят нам необходимую функциональность для реализации REST API продуктов. Скопируем файл Handler.java, который был сгенерирован с помощью boilerplate, и создадим четыре новых файла в папке src/main/java/com/serverless. Теперь мы можем удалить файл Handler.java.
-
CreateProductHandler.java
-
ListProductHandler.java
-
GetProductHandler.java
-
DeleteProductHandler.java
Основной код для всех обработчиков одинаков. Каждый обработчик определяется как класс, который реализует RequestHandler из среды выполнения AWS Lambda. Затем метод handleRequest переопределяется в классе, чтобы обеспечить пользовательскую логику для обработчика. Метод handleRequest получает объект Map с входными данными от вызывающей стороны и объект Context с информацией об окружении вызывающей стороны.
Создание обработчика продукта
При успешном вызове возвращается ответ 200 OK. В случае ошибки или исключения, исключение перехватывается и возвращается ответ 500 Internal Server Error:
Обработчик списка продуктов
Обработчик ListProductHandler вызывает метод list() на экземпляре продукта, чтобы получить список продуктов.
Если вызов прошел успешно, возвращается ответ 200 OK. В случае ошибки или исключения, исключение перехватывается и возвращается ответ 500 Internal Server Error:
Обработчик получения продукта
Обработчик GetProductHandler получает id через атрибут параметров пути на входе. Затем он вызывает метод get() на экземпляре продукта, передавая ему id, чтобы получить обратно подходящий продукт.
Если вызов прошел успешно, возвращается ответ 200 OK. Если продуктов с соответствующим id не найдено, возвращается ответ 404 Not Found. В случае ошибки или исключения, исключение перехватывается и возвращается ответ 500 Internal Server Error:
Обработчик удаления продукта
Обработчик DeleteProductHandler получает id через атрибут параметров пути на входе. Затем он вызывает метод delete() на экземпляре продукта, передавая ему id для удаления продукта.
При успешном вызове возвращается ответ 204 No Content. Если продуктов с соответствующим id не найдено, возвращается ответ 404 Not Found. В случае ошибки или исключения, исключение перехватывается и возвращается ответ 500 Internal Server Error:
Примечание: Полный исходный код проекта доступен на Github.
Развертывание службы
Теперь, когда мы рассмотрели код и поняли общую работу сервиса, давайте соберем Java-код и развернем сервис в облаке.
Чтобы собрать Java-код:
После успешной сборки у нас должен появиться артефакт aws-java-products-api/target/products-api-dev.jar, который мы будем использовать на этапе развертывания.
Давайте развернем службу в облаке:
После успешного развертывания у нас появятся четыре конечные точки API, как показано выше.
Вызов API
Теперь, когда у нас есть полностью функциональный REST API, развернутый в облаке, давайте вызовем конечные точки API.
Создание продукта
Теперь мы сделаем несколько вызовов, чтобы добавить несколько продуктов.
Список продуктов
Вот таблица java-products-dev DynamoDB со списком наших продуктов:
No Product(s) Found:
Получить продукт
Продукт не найден:
Удалить продукт
Продукт не найден:
Просмотр журналов CloudWatch
Мы использовали log4j.Logger в нашем Java-коде для записи соответствующей информации и ошибок в журналы. В случае AWS журналы можно получить из CloudWatch.
Давайте выполним вызов GET, а затем посмотрим на журналы в терминале:
Обратите внимание на строки об открытии/закрытии соединения с базой данных, структуре данных запроса, отправляемой в DynamoDB, а затем возвращаемой обратно, и, наконец, структуре данных ответа, возвращаемой нашим API-кодом.
Удаление службы
В любой момент времени, если вы хотите удалить сервис из облака, вы можете сделать следующее:
Это очистит все ресурсы, включая роли IAM, ведро развертывания, функции Lambda, а также удалит таблицу DynamoDB.
Резюме
Подводя итоги, мы использовали Java для создания бессерверного сервиса REST API, построили его, а затем развернули на AWS. Мы глубоко погрузились в код DAL, который обрабатывает сопоставление данных бэкенда и доступ к таблице DynamoDB. Мы также рассмотрели сопоставление событий, конечные точки API и обработчики лямбда-функций в сервисе, все это интуитивно понятно описано в файле serverless.yml.
К этому моменту у вас должна быть сквозная реализация бессерверного REST API сервиса, написанного на Java и развернутого на AWS.
Надеюсь, вам понравился этот пост, и не стесняйтесь оставлять свои отзывы или задавать вопросы в комментариях ниже.
Первоначально опубликовано на https://www.serverless.com.