ユーザーのデバイスにPush通知を送信するために、以下のような構成でアプリを開発している。この記事では、API GatewayとLambda関数を連携させて、AWS Pinpointを使用したPush通知送信を実現するための手順を解説する。Cognitoを用いた認証も組み合わせて、認証されたユーザーのみに通知を送信する安全なシステムを構築する方法を紹介する。

前提条件
- Lambda関数が作成されていること。
- Cognitoユーザープール並びに、ユーザーが作成されていること
- APIリクエストを行うために、Cognito User Poolsから
idToken
が取得できていること。
API Gatewayの設定
APIを作成
「APIを作成」からAPI作成画面に移動する。

REST APIを選択し、API名や説明などを入力してAPIを作成する。

API作成画面で設定を行う
- 新しいAPIを選択
- API名: 任意の名前を入力
- 説明: 任意
- APIエンドポイントタイプ: リージョンを選択

APIの作成が完了すると、以下のように作成ずみのAPIにアクセスできるようになる。

メソッドの作成
APIの詳細画面に遷移し、「メソッドを作成」を押下して、メソッドの作成画面に移動する。

以下の設定を行う。
- メソッドタイプ: 実装するAPIの機能に応じて「POST」「GET」などを選択する
- 統合タイプ: Lambda関数
- 該当するリージョンと関数を選択する。

メソッドを作成すると、作成したメソッドにアクセスできるようになる。

マッピングテンプレートを設定
統合リクエスト > マッピングテンプレート > 編集で、以下のJSONを追記する。

{
"body": $input.json('$'),
"headers": {
#foreach($header in $input.params().header.keySet())
"$header": "$util.escapeJavaScript($input.params().header.get($header))" #if($foreach.hasNext),#end
#end
},
"method": "$context.httpMethod",
"params": {
#foreach($param in $input.params().path.keySet())
"$param": "$util.escapeJavaScript($input.params().path.get($param))" #if($foreach.hasNext),#end
#end
},
"query": {
#foreach($queryParam in $input.params().querystring.keySet())
"$queryParam": "$util.escapeJavaScript($input.params().querystring.get($queryParam))" #if($foreach.hasNext),#end
#end
}
}
このマッピングテンプレートは、API Gatewayが受け取ったHTTPリクエストを、Lambda関数などの統合ターゲットに渡す前に変換するためのもの。具体的には、HTTPリクエストから受け取ったデータをJSONオブジェクトの形式に整形している。
以下、各セクションの説明。
- body:
$input.json('$')
- リクエストボディ全体をJSON文字列としてキャッチする。
- headers:
- HTTPリクエストのヘッダーを取得し、JSONオブジェクトの形式にマッピング。
- method:
$context.httpMethod
- リクエストのHTTPメソッド(例: GET、POST)を取得している。
- params:
- パスパラメーター(例:
/users/{userId}
のようなURLの一部として埋め込まれているもの)を取得してJSONオブジェクトの形式にマッピングしている。
- パスパラメーター(例:
- query:
- クエリパラメータ(URLの
?
の後に続くもの)を取得し、JSONオブジェクトの形式にマッピングしている。
- クエリパラメータ(URLの
Cognitoユーザープールオーソライザーを適用する
この作業は、Amazon API Gateway の API にアクセスできるユーザーを制御するために行う。APIを公開するとエンドポイントのURLが発行される訳だが、誰でもアクセスできてしまっては困る。
そこで、Cognitoユーザープールオーソライザーを適用し、認証されたユーザーのみAPIリクエストを行う方式にすることでセキュリティを高めている。
参照: REST API と Amazon Cognito ユーザープールを統合する
サイドメニューからオーソライザーを作成する。

以下の項目を入力して作成する。
- オーソライザー名: 適用でOK
- オーソライザーのタイプ: Cognito
- Cognitoユーザープール: 該当のものを選択
- トークンのソース: Authorization(リクエストヘッダーにAuthorizationというフィールドを持たせ、そこに認証情報を付与するため)

オーソライザーを作成すると、詳細画面からテストが実行できるようになる。実際にidTokenを使用してAPIにアクセスできるかどうかを検証できる。

以下のコマンドを実行し、ユーザーの認証情報を取得する。
aws cognito-idp admin-initiate-auth --user-pool-id ${ユーザープールID} --client-id ${アプリクライアントID} --auth-flow ADMIN_NO_SRP_AUTH --auth-parameters USERNAME=xxxxx,PASSWORD=xxxxx
コマンド実行後に以下のエラーが出る場合、IAMユーザーがcognito-idp:AdminInitiateAuth
操作を実行する権限がないので、設定する必要がある。IAM (Identity and Access Management)コンソールにて、対象ユーザーにポリシー(AmazonCognitoPowerUser)をアタッチすることで取得できるようになる。
An error occurred (AccessDeniedException) when calling the AdminInitiateAuth operation: User: xxx is not authorized to perform: cognito-idp:AdminInitiateAuth on resource: xxx because no identity-based policy allows the cognito-idp:AdminInitiateAuth action
IdTokenが取得できたら、その値を使ってオーソライザーをテストする。
認証に成功した場合、ステータスコード200が返ってくる。

テストに成功した場合は、クライアント(フロントエンド)側からAPIを呼ぶ際に、リクエストヘッダーに適切なidTokenを指定してあげれば、APIの認証を通過してLambda関数を実行する処理が走る。認証に成功しない場合、Lambda関数は実行されない。
APIをデプロイ
設定が完了したら、APIをデプロイする。(私の話だが、この作業忘れがちなので注意する)

Lambda側の設定
Lambda > 関数 > 該当の関数を選択し、トリガーを追加する。

トリガーを追加設定画面が開くので、以下の設定を行う。
- API Gateway」を選択
- Intent: 「Use existing API」を選択し、上記で作成したAPIを選択する。

上記の設定で、Lambda関数の実行トリガーがAPIになるため、クライアント(フロントエンド)側からAPIを正しくコールすれば、Lambda関数が実行される。
これでAPI GatewayとLambdaの連携は完了。
まとめ
API GatewayとLambdaを連携させて、AWS Pinpointを用いたPush通知送信を実現する手順を紹介した。API Gatewayの設定からLambdaのトリガー設定までの一連のプロセスを通じて、認証されたユーザーのみに通知を送信する仕組みを構築できる。さらに、Cognitoを活用することで、APIへのアクセスを制限し、セキュアな環境での運用を可能にした。この手順を実行することで、クラウド環境を利用した柔軟かつ安全なPush通知システムが構築できるだろう。
コメント