Accessing subitems in api gateway response mapping - amazon-web-services

I'm trying to do a mapping in an api gateway and I can't manage to access the children objects inside the returned json. This is my case:
When I test the endpoint directly in the api gateway I get this response:
{
"status": "FAIL",
"output": {
"errorCode": "my code",
"message": "my message"
}
}
And the api gateway integration response mapping is as follows:
#set($inputRoot = $input.path("$.output"))
$inputRoot
But I just want to return the json inside the output key, so I tried the following:
#set($inputRoot = $input.path("$.output"))
$inputRoot.output
And when I run it a get no data.
Before the transformation, the return value is
{
"output":"{\"status\":\"FAIL\",\"output\":{\"errorCode\":\"my code\",\"message\":\"my message\"}}"
}
I think that the fact that is returned as string might have something to do, but I've tried with $util.parseJson and $util.escapeJavaScript and I had no luck.
Does anyone know how can I solve this? I can't change the integration response, I have to do it through the api gateway mapping.

It should be JSON-like:
#set($inputRoot = $input.path("$.output"))
{
"output": "$inputRoot"
}

Related

How do I map a value from the method request body into an API gateway mapping template?

I have a lambda, written in Java, that accepts a Request Object of the structure
{
"id": "1",
"value": "foobar"
}
When I call this Lambda through the test interface with such an object, it works fine.
I want to create an API where a PUT request to /items/1 (i.e. of the form /items/{id}), with a request body of
{
"value": "foobar"
}
calls this Lambda.
I have created the API resourcesitems, and {id} appropriately.
And I have created the PUT method (on /items/{id}) and associated it to the lambda.
I have created a mapping template that maps the id from the path to the object.
{
"id": "$method.request.path.id"
}
However, how do I map the value from the request body into the template so that I get an integration request of the form
{
"id": "1", // came from path
"value": "foobar" // came from HTTP request body
}
How do I achieve this mapping?
Try this application/json mapping template:
{
"id": "$method.request.path.id",
"body" : $input.json('$')
}
Then in your lambda: console.log(event.body)
API Gateway mapping template and access logging variable reference
I found that this in the template works.
#set($inputRoot = $input.path('$'))
{
"id": "$method.request.path.id",
"value": $inputRoot.value
}

AWS PinPoint - SMS Message From Postman

I'm trying to initiate a SMS message using Postman, but I keep getting a response indicating "Invalid Request Body". I can't seem to find a good example on the AWS documentation (Is it just me or does anyone else encounter this with AWS?)
Below is the request body I'm submitting with my request. Any help would be much appreciated!
{
"ApplicationId": "<MyApplicationID>",
"MessageRequest": {
"Addresses": {
"[{{Destination}}]": {
"BodyOverride": "Test",
"ChannelType": "SMS"
}
},
"MessageConfiguration": {
"SMSMessage": {
"Body": "Test",
"SenderId": "Test",
"MessageType": "TRANSACTIONAL",
"Keyword": "<MyKeyword>",
"OriginationNumber": "<Origination number in E.164 Format>"
}
}
}
}
Looking at the Amazon Pinpoint SendMessages REST API, the request body doesn't include either the application-id key or MessageRequest key.
Resolution:
You will need to put the Amazon Pinpoint application-id in the URI part (or create an environmental variable) and then specify the request body as shown below :
Hope this helps!

Not able to add data into DynamoDB using API gateway POST method

I made a Serverless API backend on AWS console which uses API Gateway, DynamoDB, Lambda functions.
Upon creation I can add the data in dynamoDB online by adding a JSON file, which looks like this:
{
"id": "4",
"k": "key1",
"v": "value1"
}
But when I try to add this using "Postman", by adding the above JSON data in the body of POST message, I get a Positive return (i.e. no errors) but only the "id" field is added in the database and not the "k" or "v".
What is missing?
I think that you need to check on your Lambda function.
As you are using Postman to do the API calls, received event's body will be as follows:
{'resource':
...
}, 'body': '{\n\t"id": 1,\n\t"name": "ben"\n
}', 'isBase64Encoded': False
}
As you can see:
'body': '{\n\t"id": 1,\n\t"name": "ben"\n}'
For example, I will use Python 3 for this case, what I need to do is to load the body into JSON format then we are able to use it.
result = json.loads(event['body'])
id = result['id']
name = result['name']
Then update them into DynamoDB:
item = table.put_item(
Item={
'id': str(id),
'name': str(name)
}
)

AWS API gateway response body template mapping (foreach)

I am trying to save data in S3 through firehose proxied by API gateway. I have create an API gateway endpoint that uses the AWS service integration type and PutRecord action for firehose. I have the mapping template as
{
"DeliveryStreamName": "test-stream",
"Records": [
#foreach($elem in $input.path('$.data'))
{
"Data": "$elem"
}
#if($foreach.hasNext),#end
#end
]
}
Now when I test the endpoint with below JSON
{
"data": [
{"ticker_symbol":"DemoAPIGTWY","sector":"FINANCIAL","change":-0.42,"price":50.43},{"ticker_symbol":"DemoAPIGTWY","sector":"FINANCIAL","change":-0.42,"price":50.43}
]
}
JSON gets modified and shows up as below after the transformation
{ticker_symbol=DemoAPIGTWY, sector=FINANCIAL, change=-0.42, price=50.43}
: is being converted to = which is not a valid JSON
Not sure if something is wrong in the above mapping template
The problem is, that $input.path() returns a json object and not a stringified version of the json. You can take a look at the documentation here.
The Data property expects the value to be a string and not a json object. So long story short - currently there is no built in function which can revert a json object into its stringified version. This means you need to re read the current element in the loop via $input.json(). This will return a json string representation of the element, which you then can add as Data.
Take a look at the answer here which illustrates this concept.
In your case, applying the concept described in the link above would result in a mapping like this:
{
"DeliveryStreamName": "test-stream",
"Records": [
#foreach($elem in $input.path('$.data'))
{
#set($json = $input.json("$[$foreach.index]"))
"Data":"$util.base64Encode($json)",
}
#if($foreach.hasNext),#end
#end
]
}
API Gateway considers the payload data as a text and not as a Json unless explicitly specified.
Kinesis also expects data to be in encoded format while proxying through API Gateway.
Try the following code and this should work, wondering why the for loop has been commented in the mapping template.
Assuming you are not looping through the record set, the following solution should work for you.
{
"DeliveryStreamName": "test-stream",
"Record": {
"Data": "$util.base64Encode($input.json('$.Data'))Cg=="
}
}
Thanks & Regards,
Srivignesh KN

Getting response from AWS Lambda function to AWS Lex bot is giving error?

I have created one AWS Lex bot and I am invoking one lambda function from that bot. When testing the lambda function I am getting proper response but at bot I am getting below error:
An error has occurred: Received invalid response from Lambda: Can not
construct instance of IntentResponse: no String-argument
constructor/factory method to deserialize from String value
('2017-06-22 10:23:55.0') at [Source: "2017-06-22 10:23:55.0"; line:
1, column: 1]
Not sure, what is wrong and where I am missing. Could anyone assist me please?
The solution to above problem is that we need to make sure response returned by lambda function, to be used at AWS lex chat bot should be in below format:
{
"sessionAttributes": {
"key1": "value1",
"key2": "value2"
...
},
"dialogAction": {
"type": "ElicitIntent, ElicitSlot, ConfirmIntent, Delegate, or Close",
Full structure based on the type field. See below for details.
}
}
By this, chat bot expectd DialogAction and corresponding elements in order to process the message i.e. IntentResponse.
Reference: http://docs.aws.amazon.com/lex/latest/dg/lambda-input-response-format.html
no String-argument constructor/factory method to deserialize from String value
You are getting this error because you must be passing string values in the response of lambda function. You have to pass a predefined json object blueprint in the response.
Because the communication between Lex and Lambda is not simple value passing like normal functions. Amazon Lex expects output from Lambda in a particular JSON format and data is sent to Lambda in a particular JSON. The examples are here: Lambda Function Input Event and Response Format.
And just copying and pasting the blueprint won't work because in some fields you have choose between some predefined values and in some fields you have to entry valid input.
For example in,
"dialogAction": {
"type": "Close",
"fulfillmentState": "Fulfilled or Failed",
"message": {
"contentType": "PlainText or SSML",
"content": "Thanks, your pizza has been ordered."
}
}
you have assign a value "Fulfilled" or "Failed" to field 'fulfillmentState'. And same goes for 'contentType'.