Превратите любой API в механизм, управляемый событиями
Нет никаких сомнений в том, что мир стал асинхронным. Люди больше не ждут на экране загрузки по 30 минут, пока их задача выполняется незаметно. Мы придумали, как создать восхитительный опыт, который повысит продуктивность конечных пользователей, пока происходят другие дела. Мы знаем, как улучшить жизнь наших пользователей.
Это то, чего мы ожидаем в наши дни. Если программное обеспечение заставляет вас ждать и не дает чего-то хотя бы в качестве отвлечения, мы уйдем. Мы прекратим использовать ваше приложение, потому что заставлять кого-то сидеть и ждать больше невыносимо.
Это осознание может быть немного пугающим для разработчиков программного обеспечения. Вы знаете, что вам нужно создавать быстрые и хорошо масштабируемые API, но что происходит, когда ваш рабочий процесс просто занимает много времени? 2023 год привел нас прямо в мир тяжелых рабочих нагрузок, связанных с искусственным интеллектом — процессов, которые традиционно не выполняются за 250 мс или меньше. Эти потоки занимают от 30 секунд до минуты, если вам повезет, а иногда и намного больше.
Так что же нам делать? Опирайтесь на асинхронную обработку.
Запускайте фоновые задания, публикуйте обновления статуса в WebSocket, запускайте и забудьте дочерние процессы, а также активно работайте над архитектурами, управляемыми событиями, — вот что заставит нас двигаться с головокружительной скоростью инноваций. Хотя эти вещи звучат пугающе, они не так уж и плохи. Я создал кое-что, что облегчит вам задачу.
API, управляемые событиями
Я полностью за API. Я думаю, что все программное обеспечение должно быть ориентировано на API, при этом тщательно продуманы контракты и пути, из которых состоит ваше приложение. Проектирование того, как пользователи взаимодействуют с вашим API, должно быть осознанным и хорошо продуманным занятием, потому что именно так ваши клиенты сложат о вас впечатление.
Проблема многих API-интерфейсов на основе REST заключается в том, что они имеют тенденцию быть синхронными. Вы звоните и ждете ответа. Это не всегда лучше всего работает с нашими асинхронными рабочими процессами. Конечно, это необходимо для обогащения и извлечения данных, но для таких операций, как DELETE, PUT или иногда даже POST, получение обратного ответа не требуется.
Если вам не нужен ответ и вы намерены позвонить в службу и двигаться дальше, вы следуете подходу «выстрелил и забыл». AWS упрощает взаимодействие с API таким образом.
Используя назначения API EventBridge, вы можете вызвать конечную точку HTTP в качестве цели правила EventBridge. Это означает, что вы можете просто поместить событие в шину событий и продолжить рабочий процесс, поскольку конечная точка HTTP вызывается асинхронно. Довольно мило, правда?
На днях я вручную создавал направления API и правила EventBridge для интеграции Momento и подумал, что должен быть более простой способ. С целевым API задействовано лишь несколько ресурсов AWS, и большинство из них можно использовать повторно, если они ориентированы на один и тот же API. Поэтому я обратил внимание на свою спецификацию Open API.
Преобразование спецификаций Open API в назначения API
Если вы меня хоть немного знаете, то знаете, что я большой сторонник Open API. Если они написаны правильно, они содержат всю информацию, необходимую для полной интеграции с API. Он содержит информацию о сервере/среде, схемы безопасности, определения конечных точек, схемы запросов и ответов, а также список всех параметров (запрос, заголовок и путь), которые вы можете передать в любое время.
Оказывается, эта информация — это все, что вам нужно при создании направлений API! Вам понадобится полный URL-адрес вызова, параметры пути, параметры строки запроса, заголовки и информация аутентификации. Здесь есть место для счастливого процесса преобразования!
Сначала я пытался преобразовать свои спецификации в CloudFormation с помощью сценария Node на своей машине. Я заставил это работать довольно быстро, но не думал, что другие действительно будут использовать его с их характеристиками. Что-то в запуске сценария JavaScript на локальном компьютере немного отталкивает людей 😊.
Поэтому вместо этого я решил выпустить действие GitHub, чтобы вы могли включить его в свой конвейер CI и запускать по мере внесения обновлений в свою спецификацию. Это действие автоматически примет ваше определение API и создаст сценарий CloudFormation, который можно использовать для развертывания одним щелчком мыши для добавления правил EventBridge и назначений API в вашу учетную запись AWS.
Вы можете использовать этот CloudFormation для себя или разместить его за кнопкой «Запустить стек», которая открывает консоль CloudFormation и запрашивает переменные развертывания (при необходимости), как я это сделал здесь.
Давайте взглянем на определение действия и поймем некоторые предварительные требования для вашей спецификации Open API.
Определение действия
Чтобы использовать действие в своих рабочих процессах, вы можете добавить в свои конвейеры следующий шаг:
- name: Generate CloudFormation from OpenAPI spec
uses: allenheltondev/api-spec-to-api-destinations@v1
with:
specPath: path/to/openapi/spec.yaml
blueprint: path/to/template.yaml
environment: prod
httpMethods: POST,DELETE,PUT
resourcePrefix: MYAPP
outputFilename: template.yaml
Давайте поговорим об этом:
Имя | Описание | Required |
specPath | Путь к спецификации OpenAPI. | ✅ |
blueprint | Путь к файлу шаблона, который вы хотите использовать в качестве основы. Полезно, если вам нужно предоставить параметры аутентификации. | ❌ |
environment | Значение в поле «Описание» сервера в вашей спецификации OpenAPI. Используется для получения базового пути к местам назначения API. По умолчанию используется первый сервер, если он не указан. | ❌ |
httpMethods | Список разделенных запятыми методов HTTP для преобразования в пункты назначения API (например, «GET,POST,PUT,DELETE»). | ❌ |
resourcePrefix | Prefix, используемый для всех созданных ресурсов. | ❌ |
outputFilename | Имя файла для сгенерированного вывода. По умолчанию используется «template.yaml», если он не указан. | ❌ |
Это относительно простое действие, и каждое из необязательных полей имеет значимое значение по умолчанию.
Требования к открытому API
Что мне больше всего нравится в ОАГ, так это мало места для двусмысленности. Это четкая спецификация, которая точно определяет, что можно, а что нельзя иметь во всем файле. Благодаря этому мы можем делать предположения при построении интеграций и преобразований, поскольку мы знаем формат и расположение всех данных, к которым нам нужно получить доступ. Итак, давайте поговорим о необязательных полях, которые вам нужно включить в вашу спецификацию, чтобы это действие работало.
- Вы должны включить в свою спецификацию как минимум 1 сервер — они представляют вашу среду (dev, stage, prod). Вы передаете значение из описания сервера в аргументе среды действия. Это сообщает действию, какой базовый URL-адрес имеет ваш API.
- Включите идентификатор операции для каждой конечной точки. Это однозначно идентифицирует путь и метод http, предоставляя нам подробный тип EventBridge.
- Любой поддерживаемый параметр строки запроса должен быть определен в спецификации. Это будет использоваться для создания входного преобразователя для ваших правил EventBridge.
Конечно, остальная часть вашей спецификации должна быть правильно определена, например, определения пути и параметры пути. Пример спецификации вы можете посмотреть здесь.
Ограничения
Ладно, время для плохих новостей. Нам нужно охватить то, что еще не поддерживается в этом решении.
- Пользовательские заголовки не поддерживаются.
- Только аутентификация по ключу API
Если вы хотите обновить исходный код, чтобы добавить поддержку заголовков или других форм аутентификации, помимо ключей API, я принимаю запросы на включение! Но на данный момент только параметры пути, параметры строки запроса и ключи API.
События EventBridge
После развертывания сгенерированного стека CloudFormation вы можете сразу же начать вызывать свои конечные точки через EventBridge. Используя данные из вашей спецификации, создаются правила EventBridge, которые сопоставляют значения из полезных данных события с конечной точкой вашего API.
Давайте возьмем пример конечной точки из теоретической спецификации Open API, которая добавляет отчет о травме футболисту:
paths:
/players/{playerId}/injuries:
parameters:
- name: playerId
in: path
required: true
schema:
type: string
post:
parameters:
- name: followUpDate
in: query
required: false
schema:
type: string
format: date
operationId: Add Player Injury
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
type:
type: string
injuryDate:
type: string
format: date
required:
- type
- injuryDate
Эта конечная точка имеет параметр пути playerId
и параметр строки запроса FollowUpDate
. Также требуется полезная нагрузка JSON в теле запроса со свойствами типа и повреждения.
Если бы мы активировали эту конечную точку с помощью нашего правила EventBridge, это могло бы выглядеть примерно так с помощью AWS SDK v3 для JavaScript:
import { EventBridgeClient, PutEventsCommand } from '@aws-sdk/client-eventbridge';
const events = new EventBridgeClient();
await events.send(new PutEventsCommand({
Entries: [
{
Source: 'my-football-app',
DetailType: 'Add Player Injury',
Detail: JSON.stringify({
playerId: "7"
followUpDate: "2023-10-31"
message: {
type: "Ankle sprain",
injuryDate: "2023-09-20"
}
})
}
]
}));
Как видите, мы использовали идентификатор операции в качестве DetailType события, параметры пути и запроса являются свойствами корневого уровня в деталях, а тело нашего запроса содержится в свойстве massage
. Вот и все! Это приведет к асинхронному вызову нашей конечной точки, пока мы продолжаем рабочий процесс.
Возьмите это на себя
Это очень простой способ асинхронного вызова вызовов API. Возьмите свою спецификацию и преобразуйте ее в события. Бум готов.
Конечно, это работает не для всех случаев использования. Доставка может оказаться неудачной из-за проблем с сетью или неправильного ввода. В таких случаях они автоматически направляются в очередь недоставленных писем. Обязательно следите за этим! Проблема подхода «выстрелил и забыл» — это обработка ошибок и отказоустойчивость (то есть разработка промышленного уровня).
Но во многих случаях это действительно работает, и я настоятельно рекомендую вам его использовать! Назначения API дешевы — они стоят 0,20 доллара за миллион вызовов, что равно стоимости Lambda за вычетом времени вычислений. Ваши учетные данные API бесплатно сохраняются в Secrets Manager при создании целевого соединения API, что еще больше снижает ваши расходы!
Мне нравится эта форма вызова, потому что она открывает двери для множества возможностей, включая прямую интеграцию с Step Functions! Вместо вызова функции Lambda или конечной точки прокси-шлюза API просто отбросьте событие. Так просто и это просто работает.
Дайте мне знать, если вы попробуете это или захотите внести свой вклад, небольшая помощь имеет большое значение!
Приятного кодирования!