How to pass a querystring or route parameter to AWS Lambda from Amazon API Gateway
Asked Answered
B

23

503

for instance if we want to use

GET /user?name=bob

or

GET /user/bob

How would you pass both of these examples as a parameter to the Lambda function?

I saw something about setting a "mapped from" in the documentation, but I can't find that setting in the API Gateway console.

  • method.request.path.parameter-name for a path parameter named parameter-name as defined in the Method Request page.
  • method.request.querystring.parameter-name for a query string parameter named parameter-name as defined in the Method Request page.

I don't see either of these options even though I defined a query string.

Bethanybethe answered 9/7, 2015 at 23:20 Comment(0)
S
526

As of September 2017, you no longer have to configure mappings to access the request body.

All you need to do is check, "Use Lambda Proxy integration", under Integration Request, under the resource.

enter image description here

You'll then be able to access query parameters, path parameters and headers like so

event['pathParameters']['param1']
event["queryStringParameters"]['queryparam1']
event['requestContext']['identity']['userAgent']
event['requestContext']['identity']['sourceIP']
Sandie answered 8/9, 2017 at 10:19 Comment(3)
This is a great tip. But, keep in mind that turning on Lambda Proxy Integration could cause a "Malformed Lambda Proxy Response" error. Here's how to fix it: #43708517Swift
where is "Integration Request" located? edit: nevermind, comment below says API Gateway consoleFlorey
I think SO should add an option to pay the author for such helpful answers! Thanks mate! You saved me hours. Any idea where this is mentioned int he documentation?Wrongheaded
B
245

The steps to get this working are:

Within the API Gateway Console...

  1. Go to Resources -> Integration Request
  2. Click on the plus or edit icon next to the templates dropdown (odd I know since the template field is already open and the button here looks greyed out)
  3. Explicitly type application/json in the content-type field even though it shows a default (if you don't do this it will not save and will not give you an error message)
  4. put this in the input mapping { "name": "$input.params('name')" }
  5. click on the check box next to the templates dropdown (I'm assuming this is what finally saves it)
Bethanybethe answered 10/7, 2015 at 15:48 Comment(1)
Did you ever get this to send through URL parameters in URLs like /user/bob where the route was /user/{username}? I have tried all kinds of permutations, but have been unable to work that out.Forehanded
S
165

I have used this mapping template to provide Body, Headers, Method, Path, and URL Query String Parameters to the Lambda event. I wrote a blog post explaining the template in more detail: http://kennbrodhagen.net/2015/12/06/how-to-create-a-request-object-for-your-lambda-event-from-api-gateway/

Here is the Mapping Template you can use:

{
  "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
  }  
}
Specter answered 7/12, 2015 at 1:26 Comment(6)
Amazing! I was struggling with passing things along generically to my handler. Best answer here.Cannikin
I did this, but I am not getting anything yet. Its showing Undefined. How are we supposed to sent the Parameters in the URL? and do we need specify the variable name in the url like in a normal GET url scenario? Please help me out with this.Kunlun
Nevermind I got the result. The problem was, I added the mapping and just saved it, and did not deploy the api once again. Once I deployed the api with the new mapping, it worked just fine. Thanks a ton.Kunlun
@shashu10 See my answerOleoresin
I can't begin to tell you how useful your blog is. I found the "eturn-html-from-aws-api-gateway" post first and followed it, because it's exactly what I needed. Now I need to pass some parameters in to the function and modify the html based on that - and again you're the only one with a real guide! All the other guides I've found seem to miss the point.Carpous
This is the best answer. pathParams didn't work for me, but I got it with "uri": "$context.path". I'm not using proxy or CORS.Dantzler
I
47

These days a drop-down template is included in the API Gateway Console on AWS.

For your API, click on the resource name... then GET

Expand "Body Mapping Templates"

Type in

application/json

for Content-Type (must be explicitly typed out) and click the tick

A new window will open with the words "Generate template" and a dropdown (see image).

Select

Method Request passthrough

enter image description here

Then click save

To access any variables, just use the following syntax (this is Python) e.g. URL:

https://yourURL.execute-api.us-west-2.amazonaws.com/prod/confirmReg?token=12345&uid=5

You can get variables as follows:

from __future__ import print_function

import boto3
import json

print('Loading function')


def lambda_handler(event, context):
    print(event['params']['querystring']['token'])
    print(event['params']['querystring']['uid'])

So there is no need to explicitly name or map each variable you desire.

Incompliant answered 19/4, 2016 at 11:48 Comment(1)
how to access path param ?Balfore
P
30

In order to pass parameters to your lambda function you need to create a mapping between the API Gateway request and your lambda function. The mapping is done in the Integration Request -> Mapping templates section of the selected API Gateway resource.

Create a mapping of type application/json, then on the right you will edit (click the pencil) the template.

A mapping template is actually a Velocity template where you can use ifs, loops and of course print variables on it. The template has these variables injected where you can access querystring parameters, request headers, etc. individually. With the following code you can re-create the whole querystring:

{
    "querystring" : "#foreach($key in $input.params().querystring.keySet())#if($foreach.index > 0)&#end$util.urlEncode($key)=$util.urlEncode($input.params().querystring.get($key))#end",
    "body" : $input.json('$')
}

Note: click on the check symbol to save the template. You can test your changes with the "test" button in your resource. But in order to test querystring parameters in the AWS console you will need to define the parameter names in the Method Request section of your resource.

Note: check the Velocity User Guide for more information about the Velocity templating language.

Then in your lambda template you can do the following to get the querystring parsed:

var query = require('querystring').parse(event.querystring)
// access parameters with query['foo'] or query.foo
Pinole answered 15/10, 2015 at 8:15 Comment(1)
This is the best solution. Please remember to do Actions>Deploy API then (I wasted my time forgetting this...). The associated lambda arn will take the change immediately after the deployment. You can check it in Stages > #stage (like: prod) > Deployment History.Dit
S
26

The accepted answer worked fine for me, but expanding on gimenete's answer, I wanted a generic template I could use to pass through all query/path/header params (just as strings for now), and I came up the following template. I'm posting it here in case someone finds it useful:

#set($keys = [])
#foreach($key in $input.params().querystring.keySet())
  #set($success = $keys.add($key))
#end

#foreach($key in $input.params().headers.keySet())
  #if(!$keys.contains($key))
    #set($success = $keys.add($key))
  #end
#end

#foreach($key in $input.params().path.keySet())
  #if(!$keys.contains($key))
    #set($success = $keys.add($key))
  #end
#end

{
#foreach($key in $keys)
  "$key": "$util.escapeJavaScript($input.params($key))"#if($foreach.hasNext),#end
#end
}
Sivas answered 18/10, 2015 at 15:53 Comment(2)
Fab, I wanted to be able to use the same function for both POST (with JSON body) requests and GET with query strings. Works a dream. Thanks!Lahey
@benv is this the full template?Detective
N
20

As part of trying to answer one of my own questions here, I came across this trick.

In the API Gateway mapping template, use the following to give you the complete query string as sent by the HTTP client:

{
    "querystring": "$input.params().querystring"
}

The advantage is that you don't have to limit yourself to a set of predefined mapped keys in your query string. Now you can accept any key-value pairs in the query string, if this is how you want to handle.

Note: According to this, only $input.params(x) is listed as a variable made available for the VTL template. It is possible that the internals might change and querystring may no longer be available.

Netsuke answered 6/8, 2015 at 13:32 Comment(2)
This still works as of May 2017 but it returns the JS object that API Gateway creates for you rather than the actual query string. This is annoying for me because I'm trying to parse the query string to turn repeated params into an array.Illicit
$input.params().querystring won't return a json object, it will produce something like: {"querystring" : {param1=value1, param2=value2}}Schalles
P
15

The query string is straight forward to parse in javascript in the lambda

for GET /user?name=bob

 var name = event.queryStringParameters.name;

This doesn't solve the GET user/bob question though.

Profane answered 13/6, 2016 at 1:57 Comment(2)
its event.queryStringParameters.nameGagarin
I had to do event.queryStringParameters.nameIndicate
E
15

Now you should be able to use the new proxy integration type for Lambda to automatically get the full request in standard shape, rather than configure mappings.

see: http://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-set-up-simple-proxy.html#api-gateway-set-up-lambda-proxy-integration-on-proxy-resource

Ethelethelbert answered 27/9, 2016 at 17:1 Comment(2)
I'm not sure why, but the proxy integration usually doesn't work for me. I had to remove it from the latest APIs I've created.Amperage
same ^ furthermore I've had CORS issues with API Gateway. Following along with AWS docs I was not able to get CORS working. However I found an old Medium article from mid-late 2015 which had a manual way of setting up CORS and that worked.Samoyedic
B
14

GET /user?name=bob

{
    "name": "$input.params().querystring.get('name')"
}

GET /user/bob

{
    "name": "$input.params('name')"
}
Bouse answered 19/11, 2017 at 21:44 Comment(0)
F
9

A lot of the answers here are great. But I wanted something a little simpler. I wanted something that will work with the "Hello World" sample for free. This means I wanted a simple produces a request body that matches the query string:

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

I think the top answer produces something more useful when building something real, but for getting a quick hello world running using the template from AWS this works great.

Fabled answered 13/5, 2016 at 11:4 Comment(0)
O
7

The following parameter-mapping example passes all parameters, including path, querystring and header, through to the integration endpoint via a JSON payload

#set($allParams = $input.params())
{
  "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
  }
}

In effect, this mapping template outputs all the request parameters in the payload as outlined as follows:

{
  "parameters" : {
     "path" : {    
       "path_name" : "path_value", 
       ...
     }
     "header" : {  
       "header_name" : "header_value",
       ...
     }
     'querystring" : {
       "querystring_name" : "querystring_value",
       ...
     }
   }
}

Copied from the Amazon API Gateway Developer Guide

Oleoresin answered 21/8, 2016 at 20:28 Comment(0)
A
6

For getting query parameters you get them in queryStringParameters object like this

const name = event.queryStringParameters.name;

The second one is a clean URL. If your path is /user/{name}, to get the value you get it from pathParameters object like this

const name = event.pathParameters.name;
Antitoxic answered 27/12, 2021 at 8:54 Comment(2)
Both undefined for meWeathersby
Which is undefined the pathParameters object or in this case the name? Or is it the queryStringParameters ?Antitoxic
A
4

Python 3.8 with boto3 v1.16v - 2020 December

For configuring routes, you have to configure API Gateway to accept routes. otherwise other than the base route everything else will end up in a {missing auth token} or something other...

Once you configured API Gateway to accept routes, make sure that you enabled lambda proxy, so that things will work better,

to access routes,

new_route = event['path'] # /{some_url}

to access query parameter

query_param = event['queryStringParameters'][{query_key}]
Abbotsen answered 29/12, 2020 at 12:57 Comment(0)
D
3

As @Jonathan's answer, after mark Use Lambda Proxy integration in Integration Request, in your source code you should implement as below format to by pass 502 Bad Gateway error.

NodeJS 8.10:

exports.handler = async (event, context, callback) => {
  // TODO: You could get path, parameter, headers, body value from this
  const { path, queryStringParameters, headers, body } = event;

  const response = {
    "statusCode": 200,
    "headers": {
      "Content-Type": "application/json"
    },
    "body": JSON.stringify({
      path, 
      query: queryStringParameters,
      headers,
      body: JSON.parse(body)
    }),
    "isBase64Encoded": false
  };

  return response;
};

Don't forget deploy your resource at API Gateway before re-run your API. Response JSON just return which set in body is correct. So, you could get path, parameter, headers, body value from event

const { path, queryStringParameters, headers, body } = event;

Delamination answered 31/8, 2018 at 1:38 Comment(0)
N
3

The Lambda function expects JSON input, therefore parsing the query string is needed. The solution is to change the query string to JSON using the Mapping Template.
I used it for C# .NET Core, so the expected input should be a JSON with "queryStringParameters" parameter.
Follow these 4 steps below to achieve that:

  1. Open the mapping template of your API Gateway resource and add new application/json content-tyap:

API Gateway mapping template

  1. Copy the template below, which parses the query string into JSON, and paste it into the mapping template:

    {
    "queryStringParameters": {#foreach($key in $input.params().querystring.keySet())#if($foreach.index > 0),#end"$key":"$input.params().querystring.get($key)"#end}
    }
    
  2. In the API Gateway, call your Lambda function and add the following query string (for the example): param1=111&param2=222&param3=333

  3. The mapping template should create the JSON output below, which is the input for your Lambda function.

    {
    "queryStringParameters": {"param3":"333","param1":"111","param2":"222"}
    }
    
  4. You're done. From this point, your Lambda function's logic can use the query string parameters.
    Good luck!

Nubbly answered 22/9, 2018 at 21:9 Comment(0)
P
2
exports.handler = async (event) => {
    let query = event.queryStringParameters;
    console.log(`id: ${query.id}`);
    const response = {
        statusCode: 200,
        body: "Hi",
    };
    return response;
};
Padang answered 28/6, 2020 at 6:54 Comment(0)
E
0

You can used Lambda as "Lambda Proxy Integration" ,ref this [https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-create-api-as-simple-proxy-for-lambda.html#api-gateway-proxy-integration-lambda-function-python] , options avalible to this lambda are

For Nodejs Lambda 'event.headers', 'event.pathParameters', 'event.body', 'event.stageVariables', and 'event.requestContext'

For Python Lambda event['headers']['parametername'] and so on

Entomologize answered 9/1, 2018 at 18:6 Comment(0)
L
0

My goal was to pass a query string similar to:

 protodb?sql=select * from protodb.prototab

to a Node.js 12 Lambda function via a URL from the API gateway. I tried a number of the ideas from the other answers but really wanted to do something in the most API gateway UI native way possible, so I came up with this that worked for me (as of the UI for API Gateway as of December 2020):

On the API Gateway console for a given API, under resources, select the get method. Then select its Integration Request and fill out the data for the lambda function at the top of the page.

Scroll to the bottom and open up the mapping templates section. Choose Request Body Passthrough when there are no templates defined (recommended).

Click on Add mapping templates and create one with the content-type of application/json and hit the check mark button.

For that mapping template, choose the Method Request passthrough on the drop down list for generate template which will fill the textbox under it with AWS' general way to pass everything.

Hit the save button.

Now when I tested it, I could not get the parameter to come through as event.sql under node JS in the Lambda function. It turns out that when the API gateway sends the URL sql query parameter to the Lambda function, it comes through for Node.js as:

 var insql = event.params.querystring.sql;

So the trick that took some time for me was to use JSON.stringify to show the full event stack and then work my way down through the sections to be able to pull out the sql parameter from the query string.

So basically you can use the default passthrough functionality in the API gateway with the trick being how the parameters are passed when you are in the Lambda function.

Lateral answered 15/12, 2020 at 22:0 Comment(0)
F
0

The way that works for me is to

  1. Go to Integration Request
  2. click URL Query String Parameters
  3. click Add query string
  4. in name field put the query name, which is "name" here
  5. in Mapped From field, put "method.request.querystring.name"
Fervency answered 19/12, 2020 at 23:6 Comment(0)
S
0

My 2 cents here: Lot of answers suggest to activate the option "Use Lambda Proxy Integration" and get the parameters from $.event.queryStringParameter or $.event.pathParameters. But if you happen to have Access-Control-Allow-Origin (a.k.a. CORS) activated, keep reading.

At the time of this post, Lambda Proxy integration and CORS don't work very well together. My approach was to deactivate the checkbox of Lambda Proxy integration and manually provide a Mapping templates for both request and response as follows:

Request template for application/json:

{
  #set($params = $input.params().querystring)
  "queryStringParameters" : {
    #foreach($param in $params.keySet())
      "$param" : "$util.escapeJavaScript($params.get($param))" #if($foreach.hasNext),#end
    #end
  },
  #set($params = $input.params().path)
  "pathParameters" : {
    #foreach($param in $params.keySet())
      "$param" : "$util.escapeJavaScript($params.get($param))" #if($foreach.hasNext),#end
    #end
  }
}

Mind that I named the properties as queryStringParameters and pathParameters on purpose, to mimic the names that Lambda Proxy integration would have generated. This way my lambdas won't break if one day I activate the Lambda Proxy integration.

Response template for application/json:

#set($payload = $util.parseJson($input.json('$')))
#set($context.responseOverride.status = $payload.statusCode)
$payload.body

How do you read these in your lambda (python)? (assuming parameters are optional)

def handler(event, context):
    body = event["queryStringParameters"] or {}
    result = myfunction(**body)
    return {
        "statusCode": code,
        "headers": {
            "content-type": "application/json",
        },
        "body": result
    }
Schalles answered 2/8, 2022 at 16:32 Comment(0)
W
-1

After reading several of these answers, I used a combination of several in Aug of 2018 to retrieve the query string params through lambda for python 3.6.

First, I went to API Gateway -> My API -> resources (on the left) -> Integration Request. Down at the bottom, select Mapping Templates then for content type enter application/json.

Next, select the Method Request Passthrough template that Amazon provides and select save and deploy your API.

Then in, lambda event['params'] is how you access all of your parameters. For query string: event['params']['querystring']

Washerwoman answered 14/8, 2018 at 17:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.