Slack slash-command through AWS API Gateway to AWS Lambda (Python versus Java) - amazon-web-services

I am trying to connect a Slack slash-command to an AWS Lambda (through the AWS API Gateway).
I was able to adapt the Hello, World blueprint (written in Python) in the Lambda tutorial section. I set up an API gateway as a trigger, then had Slack POST the slash-command to the API endpoint. I had to manually decode the base64 body, then use parse_qs to convert the query string-like POST body into a dictionary, where I could then access it just fine.
My real Lambda code is currently in Java, but I've started with the java-basic sample app from the Developers Guide. I built the app, uploaded the jar, and confirmed the correct handler was being called. I set up another API gateway and pointed a different Slack slash-command at the new endpoin. It fails.
The log looks like:
java.lang.RuntimeException: An error occurred during JSON parsing
Caused by: java.io.UncheckedIOException: com.amazonaws.lambda.thirdparty.com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.lang.String` out of START_OBJECT token
at [Source: (ByteArrayInputStream); line: 1, column: 1]
I'm guessing this means Slack is sending the same query string-like argument in the POST body, and for some reason, something is expecting JSON input, not just text. I don't understand why the Python handler was okay with building up an event dictionary and making the Lambda decode the POST body, whereas the Java handler is never getting called, but is dying before that when attempting to deserialize the POST body, thinking it's JSON.
Both Lambdas and API gateways were set up with the usual defaults, AFAICT.

I solved the problem by switching to using the HandlerStream example. I can then get the "body" from the event, Base64.decodeBase64 it, then unpack the form parameters with UriParameterMap.parse.
I then process the incoming text that came from the Slack slash command and then return a string of JSON that Slack expects.

Related

how to send "messagebody" directly in api call to SQS queue via url without using postman?

i have api gateway with 3 simple backends:
2 basic api routes (/plus and /minus) backed by lambda functions
1 direct sqs queue (/sqs_send)
It means i can send via api call directly to my sqs queue.
2 lambda backend functions take 2 params 'a,b' from api call and add,subtract and show output.
https://86bwtlv5ya.execute-api.us-east-1.amazonaws.com/minus?a=10&b=20 # prints -10 in browser
https://86bwtlv5ya.execute-api.us-east-1.amazonaws.com/plus?a=10&b=20 # prints 30 in browser
The 3rd function is tricky for me. Via postman i managed to send directly to sqs like this via put request. Notice how i have to select "body" "raw" then input message. I did check the sqs queue - the msg from postman is there.
My question - what to type into my api gateway endpoint to send msg directly to sqs? Without using postman?
https://86bwtlv5ya.execute-api.us-east-1.amazonaws.com/sqs_send?mesagebody # what to type after sqs_send?
This did not work - returns {"message":"Not Found"}
https://86bwtlv5ya.execute-api.us-east-1.amazonaws.com/sqs_send?
Action=SendMessage&
MessageBody=This+is+a+test+message
Is it possible, my sqs_send api route does not work with parameters, because it is designed to only work with "messagebody" as per my settings? "Message attributes" is empty?
If I understood correctly, you want to call your API gateway endpoints by directly entering the URL into your browser's address bar.
Short answer:
Unfortunately you can't do this with your 3rd endpoint /sqs_send, because it is a PUT endpoint which the browser cannot call directly through the address bar.
Details:
Browsers usually support only HTTP GET and POST methods directly, through form submissions (which in turn is an HTML limitation, where form submissions only support these two methods). In GET method, parameters are appended to the end of the URL in the pattern example.com/?name1=value1&name2=value2. In POST method, parameters are included in the body of the request, so they're not visible in the URL itself. This means that you can only call GET endpoints by directly typing into the address bar of your browser. Your /plus and /minus are likely GET endpoints. POST endpoints must be called via HTML form submissions to include your parameters.
For calling other methods like PUT and DELETE (in addition to GET and POST), you will have to use XMLHttpRequest or the Fetch API, or some frontend framework method built around them. As your Postman screenshot shows, your third endpoint /sqs_send is a PUT, so you can't call it directly by entering the URL into the browser's address bar. If you must call it this way, you will have to convert your endpoint to a GET so that you can send your parameters via URL parameters.

AWS API Gateway to Simple Notification Service

I'm trying to use the AWS console to pass a message straight from an API Gateway into an SNS queue. All the examples I've seen seem to go via a Lambda, but all the documentation and settings seem to suggest this step isn't necessarily needed.
I've got the below setup, but keep getting the error of
Execution failed due to configuration error: No match for output mapping and no default output mapping configured. Endpoint Response Status Code: 400
The mapping template section has: "When no template matches the request Content-Type header" set which the "Help" section suggests the body (which is where the json string is posted) is passed through if I've got no template set up, but maybe I'm misunderstanding this.
What am I missing?

Can AWS API Gateway support `application/x-www-form-urlencoded` with body and query string parameters?

Numerous services can accept query string parameters in the URL when a POST request is made with Content-Type: application/x-www-form-urlencoded and other parameters in the body, but it seems AWS API Gateway cannot while also accepting query string parameters.
When I call the AWS API Gateway with a POST Mapping Template for application/x-www-form-urlencoded and query string URL parameters (with a Lambda function), I get the following error:
{
"message":"When Content-Type:application/x-www-form-urlencoded,
URL cannot include query-string parameters (after '?'):
'/prod/webhook?inputType=wootric&outputType=glip&url=...'"
}
Here is an example cURL:
curl -XPOST 'https://{myid}.execute-api.{myregion}.amazonaws.com/prod/webhook? \
inputType=wootric&outputType=glip&url=https://hooks.glip.com/webhook/ \
11112222-3333-4444-5555-666677778888' \
-d "#docs/handlers/wootric/event-example_response-created.txt" \
-H 'Content-Type: application/x-www-form-urlencoded' -v
The specific goal is to get a Wootric webhook event posted to a Lambda function using a URL with query string parameters.
You can get the code here:
https://github.com/grokify/chathooks
The Wootric event body file is here:
https://raw.githubusercontent.com/grokify/chathooks/master/docs/handlers/wootric/event-example_response-created.txt
The GitHub issue is here:
https://github.com/grokify/chathooks/issues/15
The error message seems pretty definitive but I wanted to ask:
Is there a workaround to configure an API Gateway to support both?
Is there a standards-based reason why AWS would not support this or is this just a design decision / limitation?
If there's no solution to this, is there a good lightweight solution other than deploying a hosted server solution like Heroku. Also, do other cloud services support this with their API gateway + cloud functions, like Google?
Some examples showing support for both:
jQuery example: jQuery send GET and POST parameters simultaneously at AJAX request
C# example: Accessing query string variables sent as POST in HttpActionContext
Yes,there is a workaround and the key issue is to set the mapping template that will convert string into json . Very detailed example shown in
API Gateway any content type.
Please set the request property as "Content-Type", "application/json" for your HttpURLConnection like below
connection.setRequestProperty("Content-Type", "application/json");
I had a similar problem, with a 3rd party provider using web hooks. It turns out that my provider is transforming the url path from UPPERCASE to LOWERCASE. Example the endpoint should be apigateway.com/dev/0bscur3dpathRANDOM instead apigateway.com/dev/0bscur3dpathRANDOM. You get the point.
I'm not sure if I got the point in question correctly, but if you want to access the request body that is encoded as application/x-www-form-urlencoded(or anything, actually) in your Lambda function, you should use LAMBDA_PROXY request integration type (aka tick "Use Lambda Proxy integration" checkbox) when creating a method for your resource. Then you can access the request body in event.body field as a plain text in your lambda function and parse it manually.

AWS API Gateway Method Response Status

I've seen other responses for similar questions but am horribly stuck.
Trying to set a HTTP response in API Gateway (APIGW) from a lambda function.
I get the below from hitting the APIGW end-point:
{"code":404,"body":"No products found.","statusCode":0,"successful":false}
When I try to map this to a 404 from APIGW, it never catches despite having tried just about every permutation of the response. The latest one I have in there was (in integration response):
Lambda regex: .*"404".*
Body mapping: $input.path('$')
Used a string in regex as the MIME type isn't being set to json even though the response looks like it. Have tried all sorts of variants for the body mapping.
This seems to work flawlessly for most other people but no dice; any help is appreciated.
Looks like our fancy lambda is the issue; APIGW is looking for a defined response structure (errorMessage) and handles the response as-expected once provided.
Have you heard of Lambda Proxy Integration?
With this you don't need to do all those regular expression, as the whole request/response is parse to your lambda.
You control the status code by your lambda code instead of configuring the API Gateway.

Handle Space in AWS API Gateway API URL - I am using Dynamodb Proxy

I have a AWS API Gateway - and using dynamodb to read Data from database, its running good enough if I sent a parameter without Space.
URL Pattern: API_LINK/benchmark_performance/{benchmark}
if {benchmark} is replaced with a String with a space - AWS replies with no/blank data, No Error Reported. if the parameter doesn't have space in it then it sends data correctly. I also tried using JS URI_encoder method and send it but same result
If I test the AWS API End point from AWS console (parameter has Space), then the result is shown properly but the same URL gives no data when called from Browser or angular 2 Application.
Question: What should I do at AWS API Gateway Integration Mapping, that it gives me proper output and handles the space in parameter issue.
Got the answer : http://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-mapping-template-reference.html
I used :
$util.urlDecode() (Decodes an "application/x-www-form-urlencoded" string).
how to use =>
$util.urlDecode($.input.params('yourParameterName'))
in Integration Mapping (section) of API Gateway