I have created a webhook for Twilio on AWS API Gateway, which is sending the request in application/x-www-form-urlencoded Content-Type. I am unable to write or find a mapping template for Golang.
I am following this document - link for creating the API Gateway. I am currently using the below template used in the document -
The API Gateway mapping template I am using:
#set($httpPost = $input.path('$').split("&"))
{
#foreach( $kvPair in $httpPost )
#set($kvTokenised = $kvPair.split("="))
#if( $kvTokenised.size() > 1 )
"$kvTokenised[0]" : "$kvTokenised[1]"#if( $foreach.hasNext ),#end
#else
"$kvTokenised[0]" : ""#if( $foreach.hasNext ),#end
#end
#end
}
The JSON created by API Gateway mapping template:
{
"ToCountry": "US",
"ToState": "UT",
"SmsMessageSid": "SMed65aaxxxxxx5c7938df",
"NumMedia": "0",
"ToCity": "",
"FromZip": "",
"SmsSid": "SMed65aaxxxxxx938df",
"FromState": "",
"SmsStatus": "received",
"FromCity": "",
"Body": "Testing+again",
"FromCountry": "IN",
"To": "%2B1xxxxxx848",
"ToZip": "",
"NumSegments": "1",
"MessageSid": "SMed65aa5dxxxx7938df",
"AccountSid": "AC23xxxd98",
"From": "%2B9xxxxxx90",
"ApiVersion": "2010-04-01"
}
Lambda Code(Golang)
func Handler(request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
fmt.Printf("%+v\n", request)
fmt.Println("request Body:", request.Body)
fmt.Println("request HTTPMethod:", request.HTTPMethod)
fmt.Println("request Headers:", request.Headers)
fmt.Println("request:", request.RequestContext.RequestID)
}
API Gateway Logs
(442f74ed-39e5-4372-bf85-42bf814f802f) Extended Request Id: EIaYxxMF3lQ=
(442f74ed-39e5-4372-bf85-42bf814f802f) Method request path: {}
(442f74ed-39e5-4372-bf85-42bf814f802f) Method request query string: {}
(442f74ed-39e5-4372-bf85-42bf814f802f) Method request headers: {Accept=*/*, Cache-Control=max-age=259200, X-Twilio-Signature=ZWg2v7xxxfnBlPyxE=, User-Agent=TwilioProxy/1.1, X-Forwarded-Proto=https, I-Twilio-Idempotency-Token=e5d1xxx221bc4, X-Forwarded-For=54.xxxx.227, Host=xxxxxxx.execute-api.us-east-1.amazonaws.com, X-Forwarded-Port=443, X-Amzn-Trace-Id=Root=1-5de67103-7994dbxxx0dbd872, Content-Type=application/x-www-form-urlencoded}}
(442f74ed-39e5-4372-bf85-42bf814f802f) Method request body before transformations: ToCountry=US&ToState=UT&SmsMessageSid=SMed65axxx595c7938df&NumMedia=0&ToCity=&FromZip=&SmsSid=SMed65aa5xxccdd595c7938df&FromState=&SmsStatus=received&FromCity=&Body=Good+Day&FromCountry=IN&To=%2Bxxxx848&ToZip=&NumSegments=1&MessageSid=SMed65axxxd595c7938df&AccountSid=AC23a2cbxxx65a66d98&From=%2B9xxxx5590&ApiVersion=2010-04-01
(442f74ed-39e5-4372-bf85-42bf814f802f) Endpoint request URI: https://lambda.us-east-1.amazonaws.com/2015-03-31/functions/arn:aws:lambda:us-east-1:6xxxxxxxx6:function:Twillio_connector_test/invocations
(442f74ed-39e5-4372-bf85-42bf814f802f) Endpoint request headers: {x-amzn-lambda-integration-tag=442f74ed-39e5-4372-bf85-42bf814f802f, Authorization=*****27aa7a, X-Amz-Date=20191203T142819Z, x-amzn-apigateway-api-id=xxxxx, X-Amz-Source-Arn=arn:aws:execute-api:us-east-1:69xxxx886:xxxxxxx/v1/POST/message, Accept=application/x-www-form-urlencoded, User-Agent=AmazonAPIGateway_f7504e7yc6, X-Amz-Security-Token=IQoJbxxxhQH [TRUNCATED]
(442f74ed-39e5-4372-bf85-42bf814f802f) Endpoint request body after transformations:
{
"ToCountry": "US",
"ToState": "UT",
"SmsMessageSid": "SMed65aaxxxxxx5c7938df",
"NumMedia": "0",
"ToCity": "",
"FromZip": "",
"SmsSid": "SMed65aaxxxxxx938df",
"FromState": "",
"SmsStatus": "received",
"FromCity": "",
"Body": "Good+Day",
"FromCountry": "IN",
"To": "%2B1xxxxxx848",
"ToZip": "",
"NumSegments": "1",
"MessageSid": "SMed65aa5dxxxx7938df",
"AccountSid": "AC23xxxd98",
"From": "%2B9xxxxxx90",
"ApiVersion": "2010-04-01"
}
(442f74ed-39e5-4372-bf85-42bf814f802f) Endpoint response headers: {Date=Tue, 03 Dec 2019 14:28:20 GMT, Content-Type=application/json, Content-Length=43, Connection=keep-alive, x-amzn-RequestId=168394b7-c152-4434-af02-03a03b6f3090, x-amzn-Remapped-Content-Length=0, X-Amz-Executed-Version=$LATEST, X-Amzn-Trace-Id=root=1-5de67103-7994dbxxxxbe30dbd872;sampled=0}
(442f74ed-39e5-4372-bf85-42bf814f802f) Endpoint response body before transformations: "Lambda function is completed successfully"
(442f74ed-39e5-4372-bf85-42bf814f802f) Method response body after transformations: Lambda function is completed successfully
(442f74ed-39e5-4372-bf85-42bf814f802f) Method response headers: {X-Amzn-Trace-Id=Root=1-5de67103-7994dbxxxxxxd872;Sampled=0, Content-Type=application/xml}
Lambda function logs
request: { map[] map[] map[] map[] map[] map[] { { } map[] } Good Day false}
{Resource: Path: HTTPMethod: Headers:map[] MultiValueHeaders:map[] QueryStringParameters:map[] MultiValueQueryStringParameters:map[] PathParameters:map[] StageVariables:map[] RequestContext:{AccountID: ResourceID: Stage: RequestID: Identity:{CognitoIdentityPoolID: AccountID: CognitoIdentityID: Caller: APIKey: AccessKey: SourceIP: CognitoAuthenticationType: CognitoAuthenticationProvider: UserArn: UserAgent: User:} ResourcePath: Authorizer:map[] HTTPMethod: APIID:} Body:Good Day IsBase64Encoded:false}
request Body: Good Day
request HTTPMethod:
request Headers: map[]
In the Lambda logs, I can see that only body of created JSON gets mapped to events.APIGatewayProxyRequest and not other parameters.
And the reason is The JSON created by mapping template is not in the below format -
The events.APIGatewayProxyRequest parameter in golang:
// APIGatewayProxyRequest contains data coming from the API Gateway proxy
type APIGatewayProxyRequest struct {
Resource string `json:"resource"` // The resource path defined in API Gateway
Path string `json:"path"` // The url path for the caller
HTTPMethod string `json:"httpMethod"`
Headers map[string]string `json:"headers"`
MultiValueHeaders map[string][]string `json:"multiValueHeaders"`
QueryStringParameters map[string]string `json:"queryStringParameters"`
MultiValueQueryStringParameters map[string][]string `json:"multiValueQueryStringParameters"`
PathParameters map[string]string `json:"pathParameters"`
StageVariables map[string]string `json:"stageVariables"`
RequestContext APIGatewayProxyRequestContext `json:"requestContext"`
Body string `json:"body"`
IsBase64Encoded bool `json:"isBase64Encoded,omitempty"`
}
I would appreciate it if anyone can point me to the related document. Suggestions are welcome.
It looks like you might be trying to use the Proxy Integration handler signature to work with a Lambda Custom Integration event on a specific resource. I don't believe mapping templates are relevant in the case of a Proxy Integration.
Lambda Integration
There are two main ways to use Lambda to respond to API Gateway requests. The first is to use a Lambda integration. This method usually involves transforming the request into a custom Lambda event completely up to your discretion. Most of the heavy lifting is done by API Gateway. For instance you could transform a query parameter into just a string and then feed just that string to your Lambda handler.
Or you could take a value from a header and a part from the URL and then build a JSON object to feed to your handler.
Main Points
Proxy Integration
Then there is a Proxy Integration. A Proxy Integration transforms every request sent to the resource (usually the ANY method on a {proxy+} resource) you specify in API gateway as the events.APIGatewayProxyRequest struct type defined in the events module. This takes away the need for you to transform your requests into specific events you have to specify and removes the request heavy lifting from API Gateway and drops it into your Lambda handler.
The proxy integration handler must have the following signature:
Main Points
Here is a link that explains more of the differences and some considerations for each.