Passing array query parameters with API Gateway to lambda - amazon-web-services

Can we create a Rest URL like below in API Gateway?
[GET] /employees?id=1&id=2&id=3&id=4
I do not find a way to send id array and get that array into a lambda (python) function

this is very late but I had the same issue and found the problem:
From AWS API Gateway Reference:
When a query parameter is a list type, its value must be a string of comma-separated items. For example, GET /restapis/restapi_id/deployments/deployment_id?embed=apisummary,sdksummary.
Amazon API Gateway does not support nested query parameters of the form: GET /team?user[id]=usrid on a method request. You could work around this limitation by passing an encoded map as a single parameter and serializing it as part of a mapping template or in your back-end integration.
So a fix you could use is restructuring your request such that:
[GET] /employees?id=1,2,3,4
Hope this helps!

AWS API events have a "multiValueQueryStringParameters" field which can be used instead of "queryStringParameters". It will contain value arrays for all parameters:
idArray = event["multiValueQueryStringParameters"]["id"]

Try sending array with json syntax e.g.: /employees?ids=['1','2','3']

This could help in javascript
https://www.npmjs.com/package/amazon-api-gateway-querystring
var mapQueryString = require('amazon-api-gateway-querystring');
event.params.querystring = mapQueryString(event.params.querystring);
event.params.querystring = {
"person[0][name]": "Mark",
"person[0][age]": 32,
"person[1][name]": "Luke",
"person[1][age]": 26,
"contacts[home][phone]": "+3333333333",
"contacts[home][email]": "email#email.com",
"contacts[home][twitter]": "#username"
}
// become:
event.params.querystring = {
"person": [{
"name": "Mark",
"age": 32
}, {
"name": "Luke",
"age": 26
}],
"contacts": {
"home": {
"phone": "+3333333333",
"email": "email#email.com",
"twitter": "#username"
}
}
}

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
}

Appsync response mapping template json key name change

What would be the right way to change json response key value in aws appsync response mapping template?
JSON that I get looks like this:
{
"tenant_id": 1,
"id": "bd8ce6a8-8532-47ec-8b7f-dcd1f1603320",
"header": "Header name",
"visible": true
}
and what I would like to pass forward is
{
"tenantId": 1,
"id": "bd8ce6a8-8532-47ec-8b7f-dcd1f1603320",
"header": "Header name",
"visible": true
}
Schema wants tenant id in form of tenantID and lambda returns it in form of tenant_id. I could change it in lambda but I would like to know how to do it in response mapping template.
You could do this via the response mapping template for the field you are resolving to in the following manner:
Consider the JSON response from your lambda to be stored in the response variable, then you can return something like this.
$#set($result = {
"tenantId": ${response.tenant_id},
"id": "${response.id}",
"header": "${response.header}",
"visible": $response.visible
})
$util.toJson($result)
Alternatively, you could also mutate your response from the lambda by setting a tenantId field, something like #set( $response.tenantId = $response.tenant_id ). Let me know if you still face an issue.
Thanks,
Shankar

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

How to set variable Request format in Amazon Api Gateway?

I want to make a Model for request where some part of the request structure may change.
As i don't have uniform structure here. How can i define json model for Amazon Api Gateway?
Request:
Here data inside items.{index}.data is changing according to type_id. Also we are not sure about which item with perticular type_id come at which {index}. even the type of items.{index}.data may change.
{
"name":"Jon Doe",
"items": [
{
"type_id":2,
"data": {
"km": 10,
"fuel": 20
}
},
{
"type_id": 5,
"data": [
[
"id":1,
"value":2
],
.....
]
},{
"type_id": 3,
"data": "data goes here"
},
....
]
}
How should i do this?
API Gateway uses JSON schema for model definitions. You can use a union datatype to represent your data object. See this question for an example of such a datatype.
Please note that a data model such as this will pose problems for generating SDKs. If you need SDK support for strictly typed languages, you may want to reconsider this data model.

requestParameters returning "Invalid mapping expression specified: true"

I'm configuring a lambda function's API gateway integration with the Serverless Framework version 0.4.2.
My problem is with defining an endpoint's request parameters. The AWS docs for API gateway entry says:
requestParameters
Represents request parameters that can be accepted by Amazon API Gateway. Request parameters are represented as a key/value map, with a source as the key and a Boolean flag as the value. The Boolean flag is used to specify whether the parameter is required. A source must match the pattern method.request.{location}.{name}, where location is either querystring, path, or header. name is a valid, unique parameter name. Sources specified here are available to the integration for mapping to integration request parameters or templates.
As I understand it, the config in the s-function.json is given directly to the AWS CLI, so I've specified the request parameters in the format:
"method.request.querystring.startYear": true. However, I'm receiving an Invalid mapping expression specified: true error. I've also tried specifying the config as "method.request.querystring.startYear": "true" with the same result.
s-function.json:
{
"name": "myname",
// etc...
"endpoints": [
{
"path": "mypath",
"method": "GET",
"type": "AWS",
"authorizationType": "none",
"apiKeyRequired": false,
"requestParameters": {
"method.request.querystring.startYear": true,
"method.request.querystring.startMonth": true,
"method.request.querystring.startDay": true,
"method.request.querystring.currentYear": true,
"method.request.querystring.currentMonth": true,
"method.request.querystring.currentDay": true,
"method.request.querystring.totalDays": true,
"method.request.querystring.volume": true,
"method.request.querystring.userId": true
},
// etc...
}
],
"events": []
}
Any ideas? Thanks in advance!
It looks like the requestParameters in the s-function.json file is meant for configuring the integration request section, so I ended up using:
"requestParameters": {
"integration.request.querystring.startYear" : "method.request.querystring.startYear",
"integration.request.querystring.startMonth" : "method.request.querystring.startMonth",
"integration.request.querystring.startDay" : "method.request.querystring.startDay",
"integration.request.querystring.currentYear" : "method.request.querystring.currentYear",
"integration.request.querystring.currentMonth" : "method.request.querystring.currentMonth",
"integration.request.querystring.currentDay" : "method.request.querystring.currentDay",
"integration.request.querystring.totalDays" : "method.request.querystring.totalDays",
"integration.request.querystring.volume" : "method.request.querystring.volume",
"integration.request.querystring.userId" : "method.request.querystring.userId"
},
This ended up adding them automatically to the method request section on the dashboard as well:
I could then use them in the mapping template to turn them into a method post that would be sent as the event into my Lambda function. Right now I have a specific mapping template that I'm using, but I may in the future use Alua K's suggested method for mapping all of the inputs in a generic way so that I don't have to configure a separate mapping template for each function.
You can pass query params to your lambda like
"requestTemplates": {
"application/json": {
"querystring": "$input.params().querystring"
}
}
In lambda function access querystring like this event.querystring
First, you need to execute a put-method command for creating the Method- Request with query parameters:
aws apigateway put-method --rest-api-id "yourAPI-ID" --resource-id "yourResource-ID" --http-method GET --authorization-type "NONE" --no-api-key-required --request-parameters "method.request.querystring.paramname1=true","method.request.querystring.paramname2=true"
After this you can execute the put-integration command then only this will work. Otherwise it will give invalid mapping error
"requestParameters": {
"integration.request.querystring.paramname1" : "method.request.querystring.paramname1",
"integration.request.querystring.paramname2" : "method.request.querystring.paramname2",
Make sure you're using the right end points as well. There are two types or some such in AWS.. friend of mine got caught out with that in the past.