Главная » Хабрахабр » Бессерверный REST API «на коленке за 5 минут»

Бессерверный REST API «на коленке за 5 минут»

Привет, Хабр! Сегодня продолжим разговор о возможностях, которые предоставляет нам Amazon Web Services и о том, как эти возможности использовать в решении прикладных задач.

На простом примере рассмотрим создание буквально за несколько минут собственного бессерверного автомасштабируемого REST API с разбором кейса — получения списка для ресурса.

Тогда заходим под кат! Интересно?


(Источник)

Вместо вступления

Для разбора примера использовать какие-либо базы данных не будем, вместо этого нашим источником информации будет обычный текстовый файл на AWS S3.

  • Итак, предположим, что на AWS S3 у нас есть текстовый файл с заголовками и некий процесс пишет в него информацию.
  • Мы создадим облачный API, который по GET запросу с переданным параметром будет возвращать в виде ответа JSON коллекции.
  • При этом, в зависимости от сложности задач и, как следствие, повышенных требований к вычислительной мощности ресурсов, не придется об этом заботиться, т.к. сервис полностью автомасштабируемый. А это означает, что не нужно никакого администрирования, выделения серверов и управления ими, просто загружаем свой код и запускаем его.

Архитектура разрабатываемой системы

Используемые компоненты Amazon Web Services:

  • Amazon S3 — объектное хранилище, которое позволяет хранить практически неограниченные объемы информации;
  • AWS Identity and Access Management (IAM) — сервис, предоставляющий возможности безопасного управления доступом к сервисам и ресурсам AWS. Используя IAM, можно создавать пользователей AWS и группы, управлять ими, а также использовать разрешения, чтобы предоставлять или запрещать доступ к ресурсам AWS;
  • AWS Lambda — сервис, позволяющий запускать код без резервирования и настройки серверов. Все вычислительные мощности автоматически масштабируются под каждый вызов. Плата взимается на основе количества запросов к функциям и их продолжительности, т.е. времени, в течение которого исполняется код.

    запросов в месяц бесплатно и 400К Гб-с. Уровень бесплатного доступа (Free tier) предполагает 1 млн. Поддерживаемые языки: Node.js, Java, C#, Go, Python

    . Будем использовать Python:

    • Библиотека boto3 — это AWS SDK для Python, позволяющий взаимодействовать с различными сервисами Amazon;
  • Amazon API Gateway — полностью управляемый сервис для разработчиков, предназначенный для создания, публикации, обслуживания, мониторинга и обеспечения безопасности API в любых масштабах. Помимо возможности использования нескольких версий одного и того же API (stages) с целью отладки, доработки и тестирования, сервис позволяет создавать бессерверные REST API при помощи AWS Lambda. Lambda выполняет код в высокодоступной вычислительной инфраструктуре, устраняя необходимость в распределении и масштабировании серверов, а также в управлении ими.

    Уровень бесплатного доступа (Free tier) для HTTP/REST API включает один миллион вызовов API в месяц в течение 12 месяцев

Подготовка данных

В качестве источника информации для формирования ответов по REST-запросу GET будет применяться текстовый файл с табуляцией в качестве разделителей полей. Информация сейчас не имеет большого значения для данного примера, но для дальнейшего использования API я выгрузил из торгового терминала Quik таблицу текущих торгов по облигациям, номинированным в российских рублях, сохранил в файле bonds.txt и поместил этот файл в специально созданный бакет AWS S3.

Примерный вид полученной информации такой, как показано на рисунке ниже:

С этим прекрасно справится AWS Lambda. Далее, необходимо написать функцию, которая будет считывать информацию из файла bonds.txt, парсить ее и выдавать по запросу. Но сначала необходимо будет создать новую роль, которая позволит созданной Lambda-функции считывать информацию из бакета, расположенного в AWS S3.

Создание роли для AWS Lambda

  1. В консоли управления AWS переходим в сервис AWS IAM и далее в закладку «Роли», нажимаем на кнопку «Create role»;

    Добавление новой Роли

  2. Роль, которую мы сейчас создадим, будет использоваться сервисом AWS Lambda для чтения информации с AWS S3. Поэтому, на следующем шаге выбираем «Select type of trusted» --> «Aws Service» и «Choose the service that will use this role» --> «Lambda» и нажимаем на кнопку «Next: Permissions»

    Роль для сервиса Lambda

  3. Теперь необходимо задать политики доступа к ресурсам AWS, которые будут использоваться во вновь созданной роли. Т.к. список политик достаточно внушителен, используя фильтр для политик укажем к нем «S3». В результате чего получим отфильтрованный список применительно к сервису S3. Отметим чекбокс напротив политики «AmazonS3ReadOnlyAccess» и нажмем на кнопку «Next: Tags».

    Политики для Роли

  4. Шаг (Add tags (optional)) – необязательный, но при желании можно указать теги для Роли. Мы этого делать не будем и перейдем к следующему шагу – Preview. Здесь необходимо задать наименование роли – «ForLambdaS3-ReadOnly», добавить описание и нажать на кнопку «Create role».

    Наименование Роли

Все, роль создана и мы можем ее использовать в дальнейшей работе.

Создание новой функции в AWS Lambda

  1. Переходим в сервис AWS Lambda и нажимаем на кнопку «Create function»:

    Создание функции

    Заполняем все поля как показано на скриншоте ниже:

    • Name – «getAllBondsList»;
    • Runtime – «Python 3.6»
    • Role – «Choose an existing role»
    • Existing role – здесь выбираем ту роль, которую мы создали выше — ForLambdaS3-ReadOnly

    Наименование и выбор роли

  2. Остается только написать код функции и проверить ее работоспособность на различных тестовых запусках. Необходимо отметить, что основным компонентом любой Lambda-функции (если используете Python) является библиотека boto3:

    import boto3 s3 = boto3.resource('s3')
    bucket = s3.Bucket('your-s3-bucket')
    obj = bucket.Object(key = 'bonds.txt')
    response = obj.get()

    Основная идея нашей Python-функции следующая:

    • Открыть файл bonds.txt;
    • Считать заголовки столбцов;
    • Разбить записи постранично (10 коллекций в нашем случае);
    • Выбрать нужную страницу;
    • Смаппить название столбцов и записей;
    • Выдать результат в виде коллекций.

    Не будем уделять много времени самому коду функции и технической реализации, здесь все довольно просто и полный код доступен в моем GitHub.

    for i in range(0, len(lines_proc)): d = dict((u''.join(key), u''.join(value)) for (key, value) in zip(headers, lines_proc[i].split("\t"))) response_body.append(d) return

    Вставим код (или напишем свой 🙂 ) в блок «Function code» и нажимаем на кнопку «Save» в правом верхнем углу экрана.

    Вставка кода

  3. Создание тестовых событий. После вставки кода, функция доступна для запуска и тестирования. Нажмем на кнопку «Test» и создадим несколько тестовых событий: запуск функции lambda_handler с разными параметрами. А именно:
    • Запуск функции с параметром 'page': '100';
    • Запуск функции с параметром 'page': '1000000';
    • Запуск функции с параметром 'page': 'bla-bla-bla';
    • Запуск функции без параметра 'page'.

    Тестовое событие Page100

    Запуск созданной функции с передачей тестового события page == 100. Как видно из скриншота ниже, функция успешно отработала, возвратила статус 200 (OK), а также набор коллекций, который соответствуют сотой странице разделенных данных при помощи пагинации.

    Запуск тестового события Page100

    Для чистоты эксперимента запустим другое тестовое событие – «PageBlaBlaBla». В этом случае функция возвращает результат с кодом 415 и комментарий, что необходимо проверить корректность переданных параметров:

    Тестовое событие PageBlaBlaBla

    Запуск события PageBlaBlaBla

Создание API

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

  • Переходим в сервис AWS API Gateway. Нажимаем на кнопку «Create API», задаем имя API – «getAllBondsList»

    Создание нового API

  • Добавляем метод GET вновь созданному API. Для этого выбираем Actions --> Create method, в появившемся раскрывающемся списке выбираем метод GET и нажимаем на галочку

    Новый метод GET

    Далее, укажем что в методе GET будет использоваться наша Lambda-функция getAllBondsList. Выбираем ее и нажимаем на кнопку Save.

    Привязка Lambda-функции

  • Проведем деплой нашего API, получив тем самым URL-адрес для вызова API.
    Нажимаем Actions --> Deploy API, и далее, Deployment stage --> New Stage

    Мы развернем сразу в PROD. Существует возможность развертывать API в разные стадии и называть эти стадии можно как угодно (например, DEV/QA/PROD).

    Deploy API

    После деплоя будет доступна ссылка на запуск вновь созданного API. Перейдем по этому URL в адресной строке браузера (или выполним команду curl в терминале) — получим вызов API и, как следствие, запуск Lambda-функции:

    URL-адрес API

    Для демонстрации работы AWS API Gateway я буду использовать приложение Postman. В нем можно достаточно комфортно отлаживать и тестировать работу API.

    Первое тестирование API

    Копируем URL со стадии PROD в Postman и посылаем запрос GET нашему API:

    Добавим поддержку параметров запроса к API.
    Кажется, что-то пошло не так… запрос GET вернул JSON-ответ с кодом 400 и подсказкой, что не задан параметр Page в запросе вызова API.

  • Поддержка переданных параметров в запросе.
    Возвращаемся в настройки GET запроса и переходим в шаг Method Request.

    Method Request

    В детальных настройках Method Request необходимо раскрыть блок URL Query String Parameters и добавить новый параметр «page» и сделать его обязательным (Required):

    Добавление параметра

    Возвращаемся на страницу Method Execution и переходим в Integration Request. Спускаемся в самый низ страницы и раскрываем блок «Mapping Templates». Выбираем «When there are no templates defined (recommended)», в поле Content-Type следует указать application/json и нажать на галочку. Прокручиваем страницу ниже и в текстовом поле вводим код, как указано на картинке ниже. После этого нажимаем на кнопку Save.

    Method Request

    Предварительно сделав деплой API, проверяем еще раз, но уже с передачей параметра «page»:

    Теперь запрос отработал успешно и вернул нам коллекции, содержащиеся на десятой странице! Это успех! Ура!

  • Осталось только защитить наш API от нежелательных посягательств извне.

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

    Перейдем в API Keys и создадим новую связку API ключей — KeyForBondsList.

    API Keys

    После того как API Key будет успешно создан, необходимо указать, что API getAllBondsList должен требовать обязательной передачи API ключа в заголовке запроса. И привязать конкретный ключ KeyForBondsList к API getAllBondsList.

    Теперь API будет требовать передачи API Key. Перейдем опять в настройки GET запроса в Method Request и сменим параметр API Key Required с false на true.

    API Key Required

    Переходим в Usage Plan и создадим новый план использования API.

    Во-первых, дадим ему имя и описание, а во-вторых, здесь же можно задать лимиты на запуск API, например, не чаще чем один запуск в секунду и т.д.

    Создание Usage Plan

    Нажимаем на Next и переходим к следующей странице, где необходимо связать стадии API с планом пользования:

    Привязка стадии к Usage Plan

    На следующей странице привязываем API Keys к плану использования API. Нажимаем на кнопку Add API Keys to Usage Plan и находим по названию созданные API Keys на предыдущих шагах:

    Привязка API Keys к Usage Plan

    Выполнив деплой и запустив еще раз вызов GET нашего API мы получаем ответ: «Forbidden», т.к. в заголовке запроса отсутствует API Key:

    Попробуем добавить его, скопировав из API Keys --> KeyForBondsList --> API key --> Show и вставим в соответствующий раздел запроса с ключом «x-api-key»:

    На этот раз запрос возвращает данные без каких-либо проблем, вызов API безопасный и защищен от злоумышленников секретным ключом API Key. Все получилось!

Выводы и итоги

В этой статье мы рассмотрели создание бессерверного автомасштабируемого REST API с применением облачных сервисов Amazon. Статья получилась не самой маленькой по объему, но я старался максимально подробно объяснить весь процесс создания API и скомпоновать всю последовательность действий.

Уверен, что после одного-двух повторений описанных в статье действий, Вы сможете поднимать свои облачные API за 5 минут и даже быстрее.

Для закрепления теоретического материала данной статьи, попробуйте оформить бесплатную годовую подписку Amazon Web Services и проделать самостоятельно вышеуказанные шаги по созданию REST API. Благодаря своей относительной простоте, дешевизне и мощности сервис AWS API Gateway раскрывает перед разработчиками широкие возможности для использования в работе и в коммерческих проектах.

Жду Ваших комментариев к статье и желаю успехов! По любым вопросам и предложениям, с удовольствием готов пообщаться.


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

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

*

x

Ещё Hi-Tech Интересное!

В России приступили к тестированию отечественного нейроинтерфейса «Нейрочат»

Эта система предназначена для пациентов с ограниченными физическими способностями. В конце прошлого года компания Neurotrand разработала вместе с партнерами программно-аппаратный комплекс с нейрогарнитурой. Это могут быть пациенты клиник, перенесшие инсульт, военные с тяжелыми ранениями, люди, получившие травму на производстве. Она ...

Зрители не могут отличить нативную картинку 4K от интерполяции

Такие выводы можно сделать из результатов российского исследования, проведённого холдингом «Ромир». Человеческого зрения недостаточно, чтобы отличить настоящее видео 4K от картинки, которую получили из изображения HDTV с помощью интерполяции. Опрошенным показывали на телеэкране фрагменты двух видеороликов и спрашивали о восприятии ...