3

I've created a lambda function and API gateway endpoint so that it echoes the query and header parameters it receives, and I want to parse the whole payload to JSON for manageability.

The received payloads is in this form:

"{Accept=*/*, 
Accept-Encoding=gzip, 
deflate, 
Accept-Language=nb-NO,nb;q=0.8,no;q=0.6,nn;q=0.4,en-US;q=0.2,en;q=0.2,sv;q=0.2,da;q=0.2, 
Authorization=COzTjCKD6VHTC, 
Cache-Control=no-cache, 
User-Agent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.87 Safari/537.36, 
Via=1.1 7822a0bcea47c939c09def064206add3.cloudfront.net (CloudFront), X-Amz-Cf-Id=Bd_gFYsmhx0jK0eKf-3sZwwRozXtFoYC5UEFDDLKWYJkq6AR_L0Cfw==, 
X-Forwarded-For=89.8.222.70, 205.251.218.72, 
X-Forwarded-Port=443, X-Forwarded-Proto=https}"

It is not trivial to parse this manually (there is no escaping in the strings). What format is this, and are there some node libs to parse this format to JSON?

My requestTemplate:

"requestTemplates": {
    "application/json": "{\"httpMethod\": \"$context.httpMethod\", \"route\": \"$input.params('route')\", \"query\": \"$input.params().querystring\", \"header\": \"$input.params().header\"}"
  },
Kenneth Lynne
  • 15,461
  • 12
  • 63
  • 79

2 Answers2

2

If you use this mapping template in API Gateway it will be parsed for you, and available in the Lambda function as event.headers.Accept-Encoding, event.headers.Accept-Language etc.

{
  "method": "$context.httpMethod",
  "body" : $input.json('$'),
  "headers": {
    #foreach($param in $input.params().header.keySet())
    "$param": "$util.escapeJavaScript($input.params().header.get($param))" #if($foreach.hasNext),#end

    #end
  },
  "queryParams": {
    #foreach($param in $input.params().querystring.keySet())
    "$param": "$util.escapeJavaScript($input.params().querystring.get($param))" #if($foreach.hasNext),#end

    #end
  },
  "pathParams": {
    #foreach($param in $input.params().path.keySet())
    "$param": "$util.escapeJavaScript($input.params().path.get($param))" #if($foreach.hasNext),#end

    #end
  },
  "stage" : "$context.stage"
}

Note that I got this from kennbrodhagen's excellent answer to this question: How to pass a querystring or route parameter to AWS Lambda from Amazon API Gateway and I just added the "stage" property to make the API Gateway Stage available in the Lambda function.

Community
  • 1
  • 1
Mark B
  • 183,023
  • 24
  • 297
  • 295
2

You may find it easier to use the [Method Request passthrough] template (available via the Generate template drop down in the console), which will turn the values into a dictionary:

##  See http://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-mapping-template-reference.html
#set($allParams = $input.params())
{
"body-json" : "$input.json('$')",
"params" : {
#foreach($type in $allParams.keySet())
    #set($params = $allParams.get($type))
"$type" : {
    #foreach($paramName in $params.keySet())
    "$paramName" : "$util.escapeJavaScript($params.get($paramName))"
        #if($foreach.hasNext),#end
    #end
}
    #if($foreach.hasNext),#end
#end
},
"stage-variables" : {
#foreach($key in $stageVariables.keySet())
"$key" : "$util.escapeJavaScript($stageVariables.get($key))"
    #if($foreach.hasNext),#end
#end
},
"context" : {
    "account-id" : "$context.identity.accountId",
    "api-id" : "$context.apiId",
    "api-key" : "$context.identity.apiKey",
    "authorizer-principal-id" : "$context.authorizer.principalId",
    "caller" : "$context.identity.caller",
    "cognito-authentication-provider" : "$context.identity.cognitoAuthenticationProvider",
    "cognito-authentication-type" : "$context.identity.cognitoAuthenticationType",
    "cognito-identity-id" : "$context.identity.cognitoIdentityId",
    "cognito-identity-pool-id" : "$context.identity.cognitoIdentityPoolId",
    "http-method" : "$context.httpMethod",
    "stage" : "$context.stage",
    "source-ip" : "$context.identity.sourceIp",
    "user" : "$context.identity.user",
    "user-agent" : "$context.identity.userAgent",
    "user-arn" : "$context.identity.userArn",
    "request-id" : "$context.requestId",
    "resource-id" : "$context.resourceId",
    "resource-path" : "$context.resourcePath"
    }
}
Bob Kinney
  • 8,870
  • 1
  • 27
  • 35
  • Is that a new feature in the console? I like how it passes all that information in the "context". – Mark B Mar 28 '16 at 15:36
  • 1
    Thanks a bunch, looks great! But where is this drop-down? – Kenneth Lynne Mar 28 '16 at 15:44
  • @MarkB This was added to the console in a recent update. There are two drop downs when modifying a template. This new template is available under the **Generate template** drop down as **[Method Request passthrough]**. – Bob Kinney Mar 28 '16 at 16:24
  • @Bob Kinney An error occurred when I tried to use this template and I figured out it is because of "body-json" : "$input.json('$')", wouldn't it be better without the quotes: "body-json" : $input.json('$')? (The problem in my case was that the json inside the quotes also uses double quotes instead of single quotes...) – Hatim Khouzaimi Apr 19 '16 at 18:32