web-dev-qa-db-ja.com

SNSと通信するAWS APIゲートウェイ

私はLambda関数によってサービスされるAPIを構築していますが、APIゲートウェイをLambda関数に直接接続するのではなく、これらを非同期にする必要があります。「AWSサービスプロキシ」を使用して SNSメッセージをパブリッシュし、Lambda関数に関連するSNSトピックをサブスクライブさせて、リクエストの配信を受信します。フローを示す画像は次のとおりです。

enter image description here

私はLambda機能とSNSとLambdaの間のpub/subメッセージングを分離してテストしましたが、APIゲートウェイからSNSへのハンドオフに苦労しています。ドキュメントは非常に軽量ですが、私が現在想定しているのは、POSTリクエストで次の属性を送信する必要があることです。

  1. Action:API-GatewayはこれをUIで設定することを提案し、Publish適切なSNSアクションであるアクション

  2. Message:POSTメッセージの本文はJSONドキュメントである必要があります。Webクライアントによって渡され、 SNSへのゲートウェイを介してプロキシされます。

  3. TopicArn:公開先のSNSトピックを示します。私の設計では、これは静的な値/エンドポイントになるので、Webクライアントもこれを渡す必要がないようにしたいのですが、これを行う方が簡単であれば問題ありません。

多くのことを試しましたが、行き詰まっています。どこかで良いコード例を見つけたいと思いますが、どんな助けでもいただければ幸いです。


私の現在の試みにもう少しコンテキストを追加したかった:

私は自分のAPIを公開し、Postmanを使用して有効な応答を取得しようとしました。これが郵便配達員の画面です(1つはヘッダー変数用、もう1つはJSON本文用)。

header variablesjson body

その結果、次のエラーメッセージが表示されます。

{
   "Error": {
     "Code": "InvalidParameter",
     "Message": "Invalid parameter: TopicArn or TargetArn Reason: no value for required parameter",
     "Type": "Sender"
  },
  "RequestId": "b33b7700-e8a3-58f7-8ebe-39e4e62b02d0"
}

エラーは、TopicArnパラメーターがSNSに送信されていないことを示しているようですが、API-Gatewayに以下を含めました:

enter image description here

17
ken

AWSサポートと連携した後、私は最終的にこれを動作させることができました。これが私の解決策です:

  • まず最初に、あなたがPOSTを送信している場合でも、not期待どおりにメッセージの本文でJSONメッセージを送信できます
  • 代わりに、JSONをURLエンコードしてクエリパラメータとして渡す必要があります
  • また、送信するJSONはdefaultのルートオブジェクトで始まる必要があります。これは、SNSの世界では「デフォルトチャネル」を意味します
  • 次に、最終的にLambdaがSNSイベントを取得し、JSONメッセージを取得するために多くのノイズを抽象化する必要もあります。このため、Lambda関数内で使用する次の関数を作成しました。
/**
 * When this is run in AWS it is run "through" a SNS
 * event wconfig.ich adds a lot of clutter to the event data,
 * this tests for SNS data and normalizes when necessary
 */
function abstractSNS(e) {
  if (e.Records) {
    return JSON.parse(decodeURIComponent(e.Records[0].Sns.Message)).default;
  } else {
    return e;
  }
}

/**
 * HANDLER
 * This is the entry point for the lambda function
 */
exports.handler = function handler(event, context) {
  parent.event = abstractSNS(event);
7
ken

私はApi Gatewayチームの出身です。

Publish APIへのHTTPリクエストにはいくつかの形式があると思いますが、最初に使用した形式は次のとおりです。

AWSリージョンus-west-2

AWSサービスSNS

AWSサブドメイン

HTTPメソッドPOST

アクション公開

==クエリ文字列==

件名「foo」
メッセージ「バー」
TopicArn 'arn:aws:sns:us-west-2:xxxxxxxxxxxx:test-api'

これは私がメッセージを公開するのに役立ちました。

さらに問題が発生した場合はお知らせください。

ジャック

9
Jack Kohn - AWS

誰かがまだ元の問題の解決策を探している場合、JSONリクエストの本文をAPIゲートウェイのみを介してSNSトピックにプロキシすることは可能です。

ケンが上で説明したようにゲートウェイを作成します。次に、本体を 統合リクエストのクエリパラメータ にプロキシします。ここで、Subject、TopicArnなどをハードコードするか、または JsonPath を使用してリクエストの本文からそれらをマッピングすることもできます。

例えば:

{
   //body
   "topic": "arn:aws:sns:1234567:topic"
}

次のようにヘッダーにマッピングできます。

method.request.body.topic
2
Garrett

私はそれを次のようにします:

WebApp-> Gateway-> Lambda(Boto3を使用してSNSで公開する)-> SNS-> Lambda

物事はもっと簡単になると思います。

1
Anand Bajpai

私は推測しているだけです(自分で試したことがありません)が、メッセージを正しく送信していないと思います...

ここのAWSのドキュメント( http://docs.aws.Amazon.com/sns/latest/api/API_Publish.html )に基づいて、POST the次のようなapplication/x-www-form-urlencodedエンコーディングのように見えるメッセージ:

POST http://sns.us-west-2.amazonaws.com/ HTTP/1.1
...
Action=Publish
&Message=%7B%22default%22%3A%22This+is+the+default+Message%22%2C%22APNS_SANDBOX%22%3A%22%7B+%5C%22aps%5C%22+%3A+%7B+%5C%22alert%5C%22+%3A+%5C%22You+have+got+email.%5C%22%2C+%5C%22badge%5C%22+%3A+9%2C%5C%22sound%5C%22+%3A%5C%22default%5C%22%7D%7D%22%7D
&TargetArn=arn%3Aaws%3Asns%3Aus-west-2%3A803981987763%3Aendpoint%2FAPNS_SANDBOX%2Fpushapp%2F98e9ced9-f136-3893-9d60-776547eafebb
&SignatureMethod=HmacSHA256
&AWSAccessKeyId=AKIAIOSFODNN7EXAMPLE
&SignatureVersion=2
&Version=2010-03-31
&Signature=vmqc4XRupKAxsDAdN4j4Ayw5LQljXMps3kss4bkDfCk%3D
&Timestamp=2013-07-18T22%3A44%3A09.452Z
&MessageStructure=json

つまり、メッセージ本文は、ブラウザがフォームデータをエンコードする方法に似ています。メッセージはJSON形式にすることができますが、フォームフィールドであるかのようにエンコードする必要があります(扱いにくい例え:))。

また、共通パラメーターのドキュメント( http://docs.aws.Amazon.com/sns/latest/api/CommonParameters.html )に基づいて、いくつかの追加の必須フィールド(通常のアクセスキー、署名など)。

API Gatewayを記述する言語を指定していません。手動でRESTリクエスト)を作成する代わりに、使用できるAWS SDKがあるかもしれません。

1
xpa1492

API Gatewayを使用して、AWSサービスプロキシとして設定することにより、Lambda関数を非同期で呼び出すことができます。設定は基本的には このGitHubサンプル と同じですが、Lambda呼び出しのURIが/ invoke /だけではなく / invoke-async / に変更される点が異なります。

1
Stefano Buliani