Webhookとは何ですか?
Webhook は、アプリケーション間のイベントドリブンな通信を促進する極めて重要なエンドポイントとして機能します。Momento 内では、特定のトピックで公開されたメッセージをリッスンするように調整された Webhook を作成できます。メッセージが Webhook の指定したトピックに一致すると、システムは Webhook をトリガーし、包括的なペイロードで呼び出します:
{
cache: string;
topic: string;
event_timestamp: number;
publish_timestamp: number;
topic_sequence_number: number;
token_id: string;
text: string; // will look something like "{\"message\": \"this is a message\" }"
}
このペイロードは、Webhookが発行されたメッセージに関連する関連データを受信することを保証し、Momentoエコシステムへのシームレスな統合を可能にします。
Momento TopicsとWebhooksを使用した多言語チャットアプリの構築
英語のみのチャット・アプリケーションの制約には限界があります。MomentoがMomento TopicsとAmazon Translateと連携してWebhookを導入したことで、ユーザーは自分の好きな言語でコミュニケーションできるようになり、言語の壁を越えて、より包括的なチャット体験ができるようになりました。
スペイン語、フランス語、ヒンディー語などの言語を簡単に切り替えることができます。
アーキテクチャ
このアプリケーションのアーキテクチャは、aws api gatewayをプロキシとして使用したラムダのrest apiで構成されています。lambdaは/translate
というルートでPOST
リクエストをリッスンし、それをMomentoにWebhookとして登録することで、イベントの受信を開始することができます。
1.Webhookの設定:
AWS API GatewayへのPOSTリクエストをトリガーするように、MomentoのWebhookを設定します。
2.Lambda関数:
POST /translate エンドポイントは、Webhook イベントをリスニングし、Momento からのリクエストを検証し、サポートされている言語に翻訳します。
3.APIゲートウェイ:
awsのAPIゲートウェイを経由して、ラムダ関数にリクエストを転送します。
はじめてみましょう
AWS LambdaとAPI Gatewayを使用して、提供されたボイラープレート・レポジトリを活用して、translate
APIを作成する手順と要件を概説しましょう:
ステップ1:Lambdaプロジェクトのセットアップ
ボイラープレートレポジトリをクローンして、Lambdaプロジェクトを初期化します。
ステップ2:translate
APIの作成とデプロイ
APIのSetUp
・/{proxy+}
エンドポイントでリクエストを処理するLambda REST APIを作成します。AWS CDKを使用してこれを行うには、こちらの例を参照してください。
・使用するwebhookルートをセットアップします。
// Import necessary libraries and modules
// declaring globally scoped variables to prevent redeclaration on every lambda invocation
const api = createAPI({
logger: true,
});
// Setting up CORS for our api
api.use((req: Request, res: Response, next: NextFunction) => {
res.cors({});
next();
});
// Required for returning CORS on errors
const errorHandler = (
error: Error,
req: Request,
res: Response,
next: NextFunction
) => {
res.cors({});
next();
};
// add our error handler as middleware
api.use(errorHandler);
api.post('/translate', async (req: Request, res: Response) => {
console.log('webhook endpoint invoked', req.body);
return res.status(200).send('success');
});
// Our handler which get invoked every time the lambda gets called
export const handler = async (
event: APIGatewayProxyEventV2,
context: Context
) => {
return api.run(event, context);
};
この例では、ウェブフック /translate
が呼び出されると、単に呼び出されたウェブフック・エンドポイントのログを記録
します。このコードをデプロイしてウェブフックとして登録し、期待通りに動作していることを確認することができます。
ステップ3: エンドポイントのURLを取得するための定型コードをデプロイ
以下のコマンドを使用して、提供されたコードをAWSアカウントにデプロイします:
npm cdk deploy
デプロイに成功すると、https://.execute-api.us-west-2.amazonaws.com/prod
のような URL が割り当てられます。このURLがbaseURL
となります。Lambda関数にルートを追加すると、このベースURLからシームレスに拡張されます。例えば、/webhooks
のルートを確立すると、対応するエンドポイントはhttps://.execute-api.us-west-2.amazonaws.com/prod/webhooks
になります。この方法は、APIエンドポイントの管理を簡素化し、Lambda関数内の様々な機能にアクセスするための明確な構造を保証します。
ステップ4: MomentoにWebhookを登録する
MomentoでWebhookを設定するには、キャッシュが必要です。お持ちでない場合は、こちらのMomento Consoleから作成してください。このガイドでは、us-west-2
リージョンの moderator
というキャッシュを使用します。しかし、どのリージョンのどのキャッシュでもシームレスに動作します。キャッシュの準備ができたら、その中にチャット公開トピック
をアクティブに監視するためのウェブフックを設定します。キャッシュに移動し、Webhooks を選択し、Webhook 名を入力し(例:moderator-webhook
)、トピック名を chat-publish
に設定し、Webhook の宛先を先ほど取得したエンドポイント URL に指定するだけです。
ステップ5: Momentoからのリクエストを検証するためにハンドラコードを更新します
MomentoでWebhookを生成すると、対応するシークレットが生成されます。シークレットを取得するには、Webhookに移動します。このシークレットをコピーして、Momento からのリクエストを検証する JavaScript スニペットを実装します。
以下のコードを実装して、APIでリクエスト・バリデーションを実行してください。オプションですが、ベストプラクティスとして実装することをお勧めします。
private didRequestComeFromMomento = (req: Request): boolean => {
const hash = crypto.createHmac("SHA3-256", process.env.THE_SIGNING_SECRET);
const hashed = hash.update(req.rawBody).digest('hex');
return hashed === req.headers['momento-signature'];
}
受信するリクエストごとにこの関数を呼び出し、リクエストがこの検証チェックに失敗した場合は 401 ステータスを返します。このステップは、Momentoからの有効なリクエストのみがAPIによって処理されることを保証するために、追加のセキュリティレイヤーを追加します。
ステップ6:他のトピックにメッセージを翻訳して公開するコードを追加します
これでリクエスト検証ロジックが整ったので、Webhook APIの残りの実装を進めることができます。
トピックにメッセージをパブリッシュするときは、JSON
オブジェクトとしてパブリッシュするのがよい方法です。私たちはこのフォーマットでメッセージを送信します。
{
"message": string;
}
これはbody.text
フィールドに文字列として表示され、そのようにパースすることができます。私たちの計画は、このメッセージ
を受け取り、私たちがサポートしている各言語に翻訳し、翻訳されたメッセージを対応するトピックに公開することです。ユーザーは、chat-en
またはchat-es
トピックを購読して、希望の言語のメッセージを聞くことができます。そのためのコードは次のようになります:
const supportedLanguagesMap = {
en: " English",
es: " Español",
fr: " Français",
ja: " 日本語",
de: " Deutsch",
hi: " हिन्दी",
zh: " 简体中文",
nl: " Dutch",
}
api.post('/translate', async (req: Request, res: Response) => {
// verifying the momento is sending these requests
if (!this.didRequestComeFromMomento(req)) {
return res.status(401).send({ message: 'unable to validate signing key' });
}
const parsedMessage = JSON.parse(req.body.text);
for (const lang of Object.keys(supportedLanguagesMap)) {
// send message to aws translate
const translateReq = new TranslateTextCommand({
SourceLanguageCode: 'auto',
TargetLanguageCode: lang,
Text: parsedMessage.message
});
const translateResp = await this.translateClient.send(translateReq);
// publish message to corresponding topic
const messageToSend = {
timestamp: req.body.publish_timestamp,
message: translateResp.TranslatedText ?? '',
}
await this.topicClient.publish('moderator-cache', `chat-${lang}`, JSON.stringify(messageToSend));
}
// return success on completion
return res.status(200).send({ message: 'success' });
});
コンソールを使ってコードをテストする
テストプロセスを簡略化するために、Momento Console の使用を強く推奨します。以下の手順に従って、提供されたバックエンドコードをインストールしてテストしてください:
・トピックコンソールに移動します。
・あなたが使用しているキャッシュを選択し、言語(chat-<lang-code>)
にサブスクライブします。例えば、chat-ja
というトピックで日本語の翻訳を購読できます。
別のブラウザータブで、トピックのchat-publishに公開します。
最初のターミナルウィンドウで翻訳されたテキストを受信しているかどうかを確認することで、Webhookのトリガーを確認します。
翻訳されたテキストを受信できない場合は、次のことを確認してください:
-指定された言語はsupportedLanguagesMapに存在している。
-Webhookを作成したapiエンドポイントは正しいかどうか。
-作成したWebhook LambdaはMomentoによって呼び出されているかどうか。
-正しいトピックでパブリッシュ/サブスクライブしているかどうか。
まとめ
このブログでは、webhook と Momento Topics を使用して、受信メッセージを変換し、fanout パターンで複数のトピックに公開する方法の例を概説しました。このバックエンドと UI の統合、および冒涜フィルタリングやメッセージ履歴の保存などの追加機能については、この GitHub リポジトリを参照してください。Vercelでホストされている動作例はこちらで見ることができます。
Webhookは、チャットメッセージをサマライザーに渡したり、耐久性のあるストアに保存したりするような非同期タスクを処理するなど、より高度なユースケースに使用できます。また、Webhook はチャット以外のアプリケーションにも使用できます。ステートマシンのトリガー、スラック通知の送信など…可能性は無限大です 😃