There is an API-Gateway - SNS integration.
Request body is application/json
Integration parameters:
Subject: method.request.body.Subject
Message: method.request.body.Message
TopicArn: 'arn:aws:sns:eu-west-1:*******:some-topic'
HTTP Headers: Content-Type='application/json'
Content handling : passthrough
Request body example:
{
"Subject": "Hello World",
"Message": "qwerty"
}
Now I'm struggling to make it pass new line characters (\n, \r\n, "\r\n" and many others combinations) inside the message to SNS. Value of 'Message' key is getting passed "as is".
Is there something I'm missing?
Related
I have a POST method which integrates with SNS. It initially accepted a TopicArn query string parameter and a Message, however to avoid client applications having knowledge of the ARN, and to move the message content into the request body, I needed to make use of an API Gateway mapping template.
I added the below Velocity (VTL) code under an application/json mapping template (fake account ID):
TopicArn=$util.urlEncode('arn:aws:sns:eu-west-2:1234567890123:MyTopic')
&Subject=$util.urlEncode('Contact form message')
&Message=$util.urlEncode($input.body)
I ran a test using the console with a body of:
{
"name": "test",
"email": "test#test.com",
"message": "test message"
}
but this returns the error:
Invalid parameter: TopicArn or TargetArn Reason: no value for required parameter
Endpoint request body after transformations: TopicArn=arn%3Aaws%3Asns%3Aeu-west-2%1234567890123%3AMyTopic
&Subject=Contact+form+message
&Message=%7B%0A++++%22name%22%3A+%22test%22%2C%0A++++%22email%22%3A+%22test%40test.com%22%2C%0A++++%22message%22%3A+%22test+message%22%0A%7D
Sending request to https://sns.eu-west-2.amazonaws.com/?Action=Publish
Received response. Status: 400
I'm not particularly familiar with VTL, but I literally copied some example syntax from AWS docs yet the TopicArn parameter doesn't appear to be passed to SNS.
Can anyone see what I've done wrong here?
I've got an API Gateway in front of a Lambda.
Successful responses from the Lambda (HTTP 2xx) have the response body forwarded.
However, for error responses (HTTP 5xx and others), the API Gateway transforms the response body using response templates.
Is there a way to avoid this? To have the original error response body from the Lambda?
In my Lambda I have this:
return callback(generalError, {
statusCode: 500,
headers:{
"content-type": "application/json"
},
body: JSON.stringify({
error: 'INTERNAL_ERROR',
description: error.message,
})
});
However, as output from the Gateway I get this:
{ "error": "Internal server error" }
Which doesn't match. The Lambdas response. It does match the response template in API Gateway:
{"message":$context.error.messageString}
However, is there a way to just proxy the original Lambda response instead of having this transformation in place?
I've found the reason why it doesn't work.
If you set a callback to a 500 error, including an object with an error field, somehow this will become the full response, regardless of the other output or real error.
Avoiding using an error field does the trick! I renamed it to serviceError and now I'm getting the responses I expected.
I want to POST form data to api gateway which then sends it to lambda for processing. However, I get
{
"message": "Could not parse request body into json: Unexpected character (\'-\' (code 45))
in numeric value: expected digit (0-9) to follow minus sign, for valid numeric value\n
at [Source: (byte[])\"----------------------------086228525798973846089611\r\nContent-
Disposition: form-data; name=\"first_name\"\r\n\r\nfake\r\n---------------------------
-086228525798973846089611\r\nContent-Disposition: form-data;
name=\"last_name\"\r\n\r\nname\r\n---------------------------
-086228525798973846089611\r\nContent-Disposition: form-data;
name=\"email\"\r\n\r\nfakename1#something.com\r\n---------------------------
-086228525798973846089611\r\nContent-Disposition: form-data; name=\"mobile\"\r\n\r\n\r\n-
---------------------------086228525798973\"[truncated 752 bytes]; line: 1, column: 3]"
}
In the cloudwatch logs I can see lambda gives this error: Lambda invocation failed with status: 400. Can't see any errors in lambda logs just api gateway logs.
My api gateway POST method looks like this:
Edit:
Adding image of form I am trying to submit that the API isn't liking:
Any ideas how to POST through to lambda without api gateway transformations or other issue?
I'm trying to receive a POST from a twilio widget, but my aws lambda (nodejs) function fails.
{"message": "Could not parse request body into json: Unrecognized token \'RecordingSource\': was expecting (\'true\', \'false\' or \'null\')\n at [Source: (byte[])\"RecordingSource=RecordVerb&RecordingSid=REd9475d9sdfw616e81995366d5f02291506b0&RecordingUrl=https%3A%2F%2Fapi.twilio.com%2F2010-04-01%2FAccounts%2FAC87e46c891a699385%2FRecordings%2FREd9466d5f02291506b0&RecordingStatus=completed&RecordingChannels=1&ErrorCode=0&CallSid=CA4a7f45753ef87894245dc95d445d8672&RecordingStartTime=Sat%2C%2021%20Mar%202020%2014%3A50%3A32%20%2B0000&AccountSid=AC8799385&RecordingDuration=2\"; line: 1, column: 17]"}
My AWS lambda function is very simple.
exports.handler = async (event) => {
console.log('-------------------------');
console.log(event);
console.log('-------------------------');
Your twilio widget is sending in application/x-www-form-urlencoded but your server is attempting to handle application/json. To send json instead is a client side configuration, and your widget will have to support such a configuration.
As #Alan suggests,
you could set the Recording Status Callback to a Twilio Function URL, which can do what you need it to do. Twilio Functions uses Node/JavaScript.
I have a http endpoint name - HE. This 'HE' endpoint connected with Lambda function 'L'.
So HE-->L
On some situation 'L' return Exception in this format :
{
"errorMessage": "Name John Doe is invalid. Exception occurred...",
"errorType": "java.lang.Exception",
"stackTrace": [
"example.Hello.handler(Hello.java:9)",
"sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)",
"sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)",
"sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)",
"java.lang.reflect.Method.invoke(Method.java:497)"
]
}
And the same returned by the 'HE' as is.
How I can use the Integration Response(AWS API Gateway) at 'HE' so it should only display the following :
{
"errorMessage": "Name John Doe is invalid. Exception occurred..."
}
I'm not sure I understand your set-up correctly. I'm assuming that your API Gateway is calling your Lambda function and that your Lambda function is returning the string you gave as an error object. In that case...
Add a new method response to your method. Set HTTP status of the method response to the HTTP status code you want to return, maybe 400 for this case.
Add a new integration response to your method.
Set the "Lambda Error Regex" of the integration response to a regex which will uniquely identify the error. ".Name . is invalid.*" should work for this case.
Set the "Method response status" to the HTTP status of the method response (400 in my example).
Hit save. Expand the integration response. Expand "Body Mapping Templates". Click "Add mapping template". Set the Content-Type to "application/json" (or whatever content type you want). Click the check box.
In the mapping template editor box, add a mapping template like this...
#set($inputRoot = $input.path('$'))
{"errorMessage" : "$input.path('$.errorMessage')"}
If I misunderstood your set-up and your API Gateway is calling an HTTP endpoint, then the approach is similar, but the terminology of some of the terms changes.