How to remove JSON schema from the response from AWS API gateway? - amazon-web-services

I'm using AWS API gateway as a proxy to DynamoDb as per this documentation:
https://aws.amazon.com/blogs/compute/using-amazon-api-gateway-as-a-proxy-for-dynamodb/
When tested in the API gateway, the result is as below:
{
"Count": 6,
"Items": [
{
"mini_description": {
"S": "A veg sandwich"
},
"item_description": {
"S": "A veg sandwich filled with a lot of healthy vegetables"
},
"id": {
"S": "6d0e0870-......-c5ccfbc0424c"
},
"image_url": {
"S": "https://......png"
},
"price": {
"N": "25"
},
"name": {
"S": "Veg Sandwich"
},
"item_type": {
"S": "Main Dish"
}
},
{
"mini_description": {
"S": "A normal hot coffee"
},.....
I need it in the following format:
{
"Count": 6,
"Items": [
{
"mini_description": "A veg sandwich",
"item_description": "A veg sandwich filled with a lot of healthy vegetables",
"id": "6d0e0870-.......-c5ccfbc0424c",
"image_url": "https://.......png",
"price": 25,
"name": "Veg Sandwich",
"item_type": "Main Dish"
},
{
"mini_description": "A normal hot coffee",............
Is there any procedure to change this through Integration response of API gateway?

I have achieved this by using the following mapping template in integration response of the GET method in API gateway:
#set($inputRoot = $input.path('$'))
{
"Items": [
#foreach($elem in $inputRoot.Items)
{
"mini_description" : "$elem.mini_description.S",
"item_description" : "$elem.item_description.S",
"id" : "$elem.id.S",
"image_url" : "$elem.image_url.S",
"price" : $elem.price.N,
"name" : "$elem.name.S",
"item_type" : "$elem.item_type.S"
}#if($foreach.hasNext),#end
#end
]
}

There is no way to unmarshall the data if you have API gateway going directly to DynamoDB. However, you can add a Lambda function in between API gateway and DynamoDB, and then use the unmarshall function from Javascript SDK (or any other preferred language) to remove the DynamoDB JSON elements.

Related

Wy do I get an error when issuing QueryCommand in nodejs sdk v3?

I am using aws node.js sdk v3. I want to do a simple query on the table using dynamodbdocumentclient. I wanted to do just a test if query works on a simple music table which is provided by aws developer guide.
const data = await this.dynamoDBDocumentClient.send(new QueryCommand({
TableName: "Music",
KeyConditionExpression: "#Artist = :artist",
ExpressionAttributeName: {
"#Artist": "artist"
},
ExpressionAttributeValues: {
":artist": "Acme Band"
},
});
But when I call this I get:
TypeError: Cannot read property '0' of undefined
When I do a simple:
const data = await.this.dynamoDBDocumentClient.send(newScanCommand({TableName: "Music"});
I am getting the correct response:
{
"AlbumTitle": {
"S": "Somewhat Famous"
},
"Awards": {
"N": "1"
},
"Artist": {
"S": "No One You Know"
},
"SongTitle": {
"S": "Call Me Today"
}
},
{
"AlbumTitle": {
"S": "Songs About Life"
},
"Awards": {
"N": "10"
},
"Artist": {
"S": "Acme Band"
},
"SongTitle": {
"S": "Happy Day"
}
},
{
"AlbumTitle": {
"S": "Songs About Sadness"
},
"Awards": {
"N": "8"
},
"Artist": {
"S": "Acme Band"
},
"SongTitle": {
"S": "Sad Day"
}
}
],
"ScannedCount": 3
}```
What am I doing wrong? I don't get why I am getting en error.
I just had the same problem, and according to this guide, the ExpressionAttributeValues must follow the DynamoDB JSON schema, being so, if your artist is a string, it should be:
...
ExpressionAttributeValues: {
":artist": {S: "Acme Band"}
},
...
Adding this, worked for me.
I think you simply have a typo here:
ExpressionAttributeName
It should be ExpressionAttributeNames (missing last letter).
However AWS-SDK is not very helpful with error messages. Use TypeScript to avoid similar issues, since it will show you, that you are using wrong field name basing on types definition.

google-cloud-recommendation How to get next page for Prediction?

I want to use predict method in order to get recommendation devided by page.
This method has pageToken parameter used for paging. The parameter should be received in the previous prediction response.
But this method in v2 API doesn't return pageToken or nextPageToken that is in v1beta1 API.
Why it disappeared? How can I get next page for prediction?
Request url is
https://retail.googleapis.com/v2/projects/{PROJECT_NUMBER}/locations/global/catalogs/default_catalog/placements/recently_viewed_default:predict
Request body is
{
"filter": "tag=(\"成人作品\") filterOutOfStockItems",
"userEvent": {
"eventType": "home-page-view",
"visitorId": "1254704470.1607003607",
"productDetails": [
{
"product": {
"id": "220604"
},
"quantity": 1
}
]
}
}
The response is here. There is no nextPageToken
{
"results": [
{
"id": "170706"
},
{
"id": "64081"
},
:
(snip)
:
{
"id": "132940"
},
{
"id": "17557"
}
],
"attributionToken": "ChQxNzkzOTg1NDI3MTk1OTMyNzU0MhACGiNvZnRlbl9wdXJjX2ZyZXF1ZW50bHlfMTYxNDMwNjk3OTQyNSIYb2Z0ZW5fcHVyY2hhc2VkX3RvZ2V0aGVyKAA"
}

Alexa SmartHome Skills : Issue with device discovery

I have written an Alexa smart home skills.
When I try to discover the device using the Alexa test or from the mobile app, the lambda is triggered.
The lambda is getting successfully executed, but I get below error in App or test in Alexa console.
I couldn't find any new Smart Home devices. If you’ve ‎n't already,
please enable the smart home skill for your device from the Alexa App.
What could be the possible issue?
Since the lambda is getting successfully executed, I don't think there is any issue with language (English(IN)) or AWS region (EU-WEST-1) , where the lambda is deployed.
I didn't see any logs on Alexa developer console
Any pointers?
Response from Lambda function -
header =
{
namespace: 'Alexa.Discovery',
name: 'Discover.Response',
payloadVersion: '3',
messageId: '785f0173-6ddb-41d8-a785-de7159c7f7ca'
}
payload =
{
"endpoints": [
{
"endpointId": "d4b87cbe6c8e490493733f260b8c2c25",
"friendlyName": "Kitchen",
"description": "Demo",
"manufacturerName": "Man1",
"displayCategories": [
"LIGHT"
],
"cookie": {
"owner": "Owner1"
},
"capabilities": [
{
"type": "AlexaInterface",
"version": "3",
"interface": "Alexa"
},
{
"type": "AlexaInterface",
"version": "3",
"interface": "Alexa.PowerController",
"properties": {
"supported": [
{
"name": "powerState"
}
],
"proactivelyReported": true,
"retrievable": true
}
},
{
"type": "AlexaInterface",
"version": "3",
"interface": "Alexa.BrightnessController",
"properties": {
"supported": [
{
"name": "brightness"
}
],
"proactivelyReported": true,
"retrievable": true
}
}
]
}
]
}
We are wrapping header and payload in the response event.
context.succeed({ event: { header: header, payload: payload } });
So far I haven't found a way to view the logs either.
I had the same problem and I realized that I was putting wrong values in some properties or schema entities like ids.
In the same way, another thing that solved me on some occasion was to place the scheme in the following way:
context.succeed({
"event": {
"header": {
"namespace": "Alexa.Discovery",
"name": "Discover.Response",
"payloadVersion": "3",
"messageId": header.messageId
},
"payload": {
"endpoints": [
{
"endpointId": "demo_id",
...
,
"cookie": {},
"capabilities": [
{
"type": "AlexaInterface",
"interface": "Alexa",
"version": "3"
},
...
]
}
]
}
}
});

Sort/sequence AWS API gateway output

tl;dr looking to sort API output from AWS API gateway
I have a dynamoDB table 'NP' with key 'id' and GSI 'atype-index'. There is no sort key.
Also, I have API gateway mapping template
{
"TableName": "NP",
"IndexName": "atype-index",
"KeyConditionExpression": "atype = :v1",
"ExpressionAttributeValues": {
":v1": {
"S": "$input.params('atype')"
}
}
}
The mapping template will extract all values in the table with GSI key matching the specified string. However, the values are extracted in no particular order, for example, the API could be:
{
"Count": 3,
"Items": [
{
"apiUrl": {
"S": “ee”
},
"webTitle": {
"S": “dd”
},
"atype": {
"S": “type”
},
"id": {
"S": "1a"
}
},
{
"apiUrl": {
"S": “dd”
},
"webTitle": {
"S": “cc”
},
"atype": {
"S": "atype"
},
"id": {
"S": “3a”
}
},
{
"apiUrl": {
"S": “cc”
},
"webTitle": {
"S": “bb”
},
"atype": {
"S": "atype"
},
"id": {
"S": “2a”
}
}
],
"ScannedCount": 3
}
How do I sort the above output by the key "apiURL" for example?
What you described is exactly what a sort key would accomplish, assuming you're using the Query API (rather than Scan).
If you add a sort key, the results will be sorted based on the sort key when querying a given partition key.
Edit: Just to clarify, there is no way to do the sort at the API GW layer in a mapping template.
You could put a Lambda function in between API GW and DDB if the overhead is worth it for your use case. Otherwise, probably better to just sort at client side.

Unable to map a list of numbers in API-Gateway

How do I create a mapping for a list of numbers object in API gateway? I am trying to post a list of integers using POST request. I tried working with NS attribute but got the Error.
Error:
{
"__type": "com.amazon.coral.service#SerializationException"
}
However, it works well when I have N attribute and post a single integer value.
Is there any way to resolve this issue?
I believe you are trying to map your request payload to DynamoDB JSON String. You can apply a velocity template like this one,
{
"TableName":"ABC",
"Item": {
"id": {
"S": "$context.requestId"
},
"name": {
"S": "$input.path('$.name')"
},
"price": {
"L": [
#set($prices=$input.path('$.price'))
#foreach($p in $prices)
{
"N": "$p"
}#if ($velocityCount < $prices.size()), #end
#end
]
}
}
}
Method Request Body:
{
"name":"Test",
"price": [1, 2, 3]
}
Endpoint Request Body:
{
"TableName": "ABC",
"Item": {
"id": {
"S": "test-invoke-request"
},
"name": {
"S": "Test"
},
"price": {
"L": [
{
"N": "1"
},
{
"N": "2"
},
{
"N": "3"
}
]
}
}
}