AWS API-Gateway communicating to SNS

|▌冷眼眸甩不掉的悲伤 提交于 2019-12-20 10:32:44

问题


I am building an API which will be serviced by Lambda functions but I need these to be asynchronous so rather than connecting the API-Gateway directly to the Lambda function I'm using the "AWS Service Proxy" to publish SNS messages and then have the Lambda function subscribe to the relevant SNS topic so it receives delivery of the requests. Here's a picture which illustrates the flow:

I have tested both the Lambda function in isolation as well pub/sub messaging between SNS and Lambda but I am struggling with the API-Gateway to SNS handoff. Documentation is quite light but what I am assuming right now is that the following attributes must be sent in the POST request:

  1. Action: the API-Gateway offers to set this in the UI and I have put in the Publish action which is the appropriate SNS action

  2. Message: the body of the POST message should be a JSON document. It would be passed by the web client and proxied through the gateway to SNS.

  3. TopicArn: indicates the SNS topic that we're publishing to. In my design this would be a static value/endpoint so I'd prefer that the web-client not have to pass this too but if it were easier to do this that would be fine too.

I have tried lots of things but am just stuck. Would love to find a good code example somewhere but any help at all would be appreciated.


Wanted to add a little more context on my current attempt:

I have tried publishing my API and using Postman to try and get a valid response. Here's the postman screens(one for header vars, one for JSON body):

This results in the following error message:

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

the error seems to indicate that the TopicArn parameter is not being sent to SNS but I have included the following in API-Gateway:


回答1:


I'm from the Api Gateway team.

I believe there are a few formats for the HTTP request to the Publish API, but here's the one I used first:

AWS Region us-west-2

AWS Service sns

AWS Subdomain

HTTP method POST

Action Publish

== query strings ==

Subject 'foo'
Message 'bar'
TopicArn 'arn:aws:sns:us-west-2:xxxxxxxxxxxx:test-api'

This worked for me to publish a message.

Let me know if you have further troubles.

Jack




回答2:


I did eventually get this to work after working with AWS support. Here's my solution:

  • First of all even though you're sending a POST you will not be able to send a JSON message in the body of the message as you might expect
  • Instead you must URL Encode the JSON and pass it as query parameter
  • Also remember that the JSON you send should start with a root object of default which in SNS-world means the "default channel"
  • Then, eventually Lambda picks up the SNS event you must also abstract away a lot of the noise to get at your JSON message. For this I created the following function that I use within my Lambda function:

/**
 * 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);



回答3:


If anybody is still looking for a solution to the original problem, proxying a JSON request body to an SNS topic via API gateway alone, it's possible.

Create the gateway as Ken describes above. Then simply proxy the body to the Integration Request's query parameters. You can also hard code Subject, TopicArn, etc here, or map those from the request's body using a JsonPath.

For example:

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

Could be mapped to a header as:

method.request.body.topic



回答4:


You could use API Gateway to invoke your Lambda function asynchronously by configuring it as an AWS service proxy. The configuration is basically the same you see in this GitHub sample, with the exception that the uri for the Lambda invocation changes to /invoke-async/ instead of just /invoke/




回答5:


I am just speculating (haven't tried this myself), but I think you are not sending the message correctly...

Based on AWS's documentation here (http://docs.aws.amazon.com/sns/latest/api/API_Publish.html), you need to POST the message in what seems to be the application/x-www-form-urlencoded encoding like this:

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

That is, the message body looks the way a browser would encode form data. Your message can be JSON formatted, but still needs to be encoded as if it was a form field (an awkward analogy :)).

Also, based on the common parameters documentation (http://docs.aws.amazon.com/sns/latest/api/CommonParameters.html), you have a number of additional required fields (the usual access key, signature and so on).

You have not specified what language you are writing your API Gateway in - there might be an AWS SDK for it that you can use, instead of trying to manually compose the REST requests).




回答6:


I would do it like:

WebApp --> Gateway --> Lambda ( Use Boto3 to publish in SNS ) --> SNS -->Lambda

I think, things will be simpler.



来源:https://stackoverflow.com/questions/34213464/aws-api-gateway-communicating-to-sns

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!