Create an API Gateway API as an AWS Lambda Proxy
Note
To integrate your API Gateway API with Lambda, you must choose a region where both the API Gateway and Lambda services are available. For region availability, see Regions and Endpoints.If your API makes only synchronous calls to Lambda functions in the back end, you should use the Lambda Function integration type. For instructions, see Build an API to Expose a Lambda Function.
If your API makes asynchronous calls to Lambda functions, you must use the AWS
Service Proxy
integration
type described in this section. The instructions apply to requests for
synchronous Lambda function invocations as well. For the asynchronous invocation, you must
explicitly add the X-Amz-Invocation-Type:Event
header to the integration
request. For the synchronous invocation, you can add the
X-Amz-Invocation-Type:RequestResponse
header to the integration request or
leave it unspecified. The following example shows the integration request of an asynchronous
Lambda function invocation:
POST /2015-03-31/functions/FunctionArn
/invocations?Qualifier=Qualifier HTTP/1.1
X-Amz-Invocation-Type: Event
...
Authorization: ...
Content-Type: application/json
Content-Length: PayloadSize
Payload
In this example, FunctionArn
is the ARN of the Lambda function
to be invoked. The Authorization
header is required by secure invocation of Lambda functions over HTTPS. For more information, see
the
Invoke
action in the AWS Lambda Developer Guide.
To illustrate how to create and configure an API as an AWS service proxy for Lambda, we
will create a Lambda function (Calc
) that performs addition (+), subtraction
(-), multiplication (*), and division (/). When a client submits a method request to perform
any of these operations, API Gateway will post the corresponding integration request to call the
specified Lambda function, passing the required input (two operands and one operator) as a
JSON payload. A synchronous call will return the result, if any, as the JSON payload. An
asynchronous call will return no data.
The API can expose a GET or POST method on the /calc
resource to invoke the
Lambda function. With the GET method, a client supplies the input to the back-end Lambda
function through three query string parameters (operand1
,
operand2
, and operator
). These are mapped to the JSON payload of
the integration request. With the POST method, a client provides the input to the Lambda
function as a JSON payload of the method request, which is then passed through to the
integration request. Alternatively, the API can expose a GET method on the
/calc/{operand1}/{operand2}/{operator}
resource. With this method, the
client specifies the Lambda function input as the values of the path parameters. Parameter
mappings and mapping templates are used to translate the method request data into the Lambda
function input and to translate the output from the integration responses to the method
response.
This section provides more detailed discussions for the following tasks:
Create the
Calc
Lambda function to implement the arithmetic operations, accepting and returning JSON-formatted input and output.Expose GET on the
/calc
resource to invoke the Lambda function, supplying the input as query strings.Expose POST on the
/calc
resource to invoke the Lambda function, supplying the input in the payload.Expose GET on the
/calc/{operand1}/{operand2}/{operator}
resource to invoke the Lambda function, specifying the input in the path parameters.
You can import the sample API as a Lambda proxy from the Swagger Definitions of a Sample API as Lambda Proxy. To do so, copy the Swagger definition, paste it into a file, and use the API Gateway Swagger Importer. For more information, see Getting Started with the API Gateway Swagger Importer.
To use the API Gateway console to create the API, you must first sign up for an AWS account.
If you do not have an AWS account, use the following procedure to create one.
To sign up for AWS
Open https://aws.amazon.com/ and choose Create an AWS Account.
Follow the online instructions.
To allow the API to invoke Lambda functions, you must have an IAM role that has appropriate IAM policies attached to it. The next section describes how to verify and to create, if necessary, the required IAM role and policies.
Topics
- Set Up an IAM Role and Policy for an API to Invoke Lambda Functions
- Create a Lambda Function in the Back End
- Create API Resources for the Lambda Function
- Create a GET Method with Query Strings to Call the Lambda Function
- Create a POST Method with a JSON Payload to Call the Lambda Function
- Create a GET Method with Path Parameters to Call the Lambda Function
- A Sample API as a Lambda Proxy in Swagger with API Gateway Extensions
Set Up an IAM Role and Policy for an API to Invoke Lambda Functions
The API will use the InvokeFunction action to call a Lambda function. At minimum, you must attach the following IAM policy to an IAM role for API Gateway to assume the policy.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "lambda:InvokeFunction",
"Resource": "*"
}
]
}
If you do not enact this policy, the API caller will receive a 500 Internal Server Error response. The response contains the "Invalid permissions on Lambda function" error message. For a complete list of error messages returned by Lambda, see the Invoke topic.
An API Gateway assumable role is an IAM role with the following trusted relationship:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Service": "apigateway.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
Create a Lambda Function in the Back End
Copy the following Lambda function and paste it into the code editor in the Lambda console.
exports.handler = function(event, context) {
//console.log('Received event:', JSON.stringify(event, null, 2));
var res = {};
res.a = event.a;
res.b = event.b;
res.op = event.op;
switch(event.op)
{
case "+":
res.c = Number(event.a) + Number(event.b);
break;
case "-":
res.c = Number(event.a) - Number(event.b);
break;
case "*":
res.c = Number(event.a) * Number(event.b);
break;
case "/":
res.c = Number(event.b)===0 ? NaN : Number(event.a) / Number(event.b);
break;
default:
res.c = "Invalid op";
}
context.succeed(res);
};
This function requires two operands (a
and b
) and an
operator (op
) from the event
input parameter. The input is a
JSON object of the following format:
{
"a": "Number" | "String",
"b": "Number" | "String",
"op": "String"
}
This function returns the calculated result (c
) and the input. For an
invalid input, the function returns either the null value or the "Invalid op" string as
the result. The output is of the following JSON format:
{
"a": "Number",
"b": "Number",
"op": "String",
"c": "Number" | "String"
}
You should test the function in the Lambda console before integrating it with the API, which is created next.
Create API Resources for the Lambda Function
The following procedure describes how to create API resources for the Lambda function.
To create API resources for Lambda functions
In the API Gateway console, create an API named LambdaGate. You can create child resources to represent different Lambda functions; in the following, you will create a single child resource of the API root.
For the simple calculator function you created, create the /calc resource off the API's root. You will expose the GET and POST methods on this resource for the client to invoke the back-end Lambda function, supplying the required input as query string parameters (to be declared as
?operand1=...&operand2=...&operator=...
) in the GET request and as a JSON payload in the POST request, respectively.You will also create the /calc/{operand1}/{operand2}/{operator} to expose the GET method to invoke the Lambda function and to supply the required input as the three path parameters (operand1, operand2, and operator).
We will show how to apply API Gateway request and response data mapping to normalize the input to the back end Lambda function.
Create a GET Method with Query Strings to Call the Lambda Function
Use the following steps to expose a GET method with query strings to call a Lambda function.
To set up the GET method with query strings to invoke the Lambda function
Choose Create Method in the API Gateway console to create a GET method for the API's /calc resource.
In the method's Set up pane, configure the method with the following settings.
You must use the POST method for the integration request when calling a Lambda function, although you can use any other HTTP verbs for the method request.
The Path override value must the URL path of the Lambda Invoke action. The path is of the following format:
/2015-03-31/functions/
FunctionName
/invocations?Qualifier=version
where
FunctionName
is the ARN of the Lambda function to be invoked. The optionalQualifier
query string can be used to select a version of the function. If it not specified, the$LATEST
version will be used.You can also add the
X-Amz-Invocation-Type: Event | RequestReponse | DryRun
header to have the action invoked asynchronously, as request and response, or as a test run, respectively. If the header is not specified, the action will be invoked as request and response. For the example shown here, this header has the default value.We will come back to setting up Mapping Templates after setting up the query string parameters to hold the input data for the Lambda function.
In Method Request for the GET method on /calc, expand the URL Query String Parameters section. Choose Add query string to add the operand1, operand2, and operator query string parameters.
Go back to Integration Request. Expand the Mapping Templates section. If necessary, in Content-Type, under application/json, choose Add mapping template. Type the following in the Mapping template editor:
{ "a": "$input.params('operand1')", "b": "$input.params('operand2')", "op": "$input.params('operator')" }
This template maps the three query string parameters declared in Method Request into designated property values of the JSON object as the input to the back-end Lambda function. The transformed JSON object will be included as the integration request payload.
You can now choose Test to verify that the GET method on the /calc resource has been properly set up to invoke the Lambda function.
Create a POST Method with a JSON Payload to Call the Lambda Function
The following steps describe how to expose a POST method with a JSON payload.
To set up the POST method with a JSON payload to invoke a Lambda function
Choose Create Method in the API Gateway console to create a POST method for the LambdaGate API's /calc resource.
In the method's Set Up panel, configure the POST method with the following settings.
Using a POST request with a JSON payload is the simplest way to invoke a Lambda function, because no mappings are needed.
You can now choose Test to verify the POST method works as expected. The following input:
{ "a": 1, "b": 2, "op": "+" }
should produce the following output:
{ "a": 1, "b": 2, "op": "+", "c": 3 }
If you would like to implement POST as an asynchronous call, you can add an InvocationType:Event
header in the method request and
map it to the X-Amz-Invocation-Type
header in the integration request, using the header mapping expression of
method.request.header.InvocationType
. You must inform the clients to include the InvocationType:Event
header in the method
request. Alternatively, you can set the X-Amz-Invocation-Type
header with the 'Event'
string literal in the integration
request, without requiring the client to include the header. The asynchronous call will return an empty response, instead.
Create a GET Method with Path Parameters to Call the Lambda Function
The following steps describe how to set up the GET method with path parameters to call the Lambda function.
To set up the GET method with URL path parameters to invoke the Lambda function
Choose Create Method in the API Gateway console to create a GET method for the API's /calc/{operand1}/{operand2}/{operator} resource.
In the method's Set up pane, configure this GET method with the following settings.
Next, we will set up Mapping Templates to translate the URL path parameters into the integration request JSON payload as the input to the Lambda function.
In Method Request for the GET method on /calc/{operand1}/{operand2}/{operator}, expand the Request Paths section to verify that the path parameters are there.
Go back to Integration Request. Expand the Mapping Templates section. If necessary, in Content-Type, under application/json, choose Add mapping template.
Type the following in the Mapping Template editor:
{ "a": "$input.params('operand1')", "b": "$input.params('operand2')", "op": #if($input.params('operator')=='%2F')"/"#{else}"$input.params('operator')"#end }
This template maps the three URL path parameters, declared when the /calc/{operand1}/{operand2}/{operator} resource was created, into designated property values of the JSON object. Because URL paths must be URL-encoded, the division operator must be specified as
%2F
instead of/
. This template maps these translations as well. The transformed JSON object will be included as the integration request payload.As another exercise, we demonstrate how to translate the JSON returned from the Lambda function to show the output as a plain text string to the caller. This involves resetting the method request's Content-Type header to "text/plain" and providing a mapping template to translate the JSON output into a plain string.
First, make sure that Content-Type header is included in the Response Headers for 200 section in Method Response.
In Integration Response, expand the 200 method response entry. Expand the Header Mappings section. In Mapping value for Content-Type, type
'text/plain'
. This header mapping expression overrides the Content-Type header with a literal string, which must be enclosed within a pair of single quotes.Next, expand the Mapping Templates section, highlight the application/json entry under the Content-Type header (of integration response), open the Mapping template editor, enter and save the following mapping script:
$input.path('$.a') $input.path('$.op') $input.path('$.b') = $input.path('$.c')
Choose Test to verify the GET method on the /calc/{operand1}/{operand2}/{operator} works as expected. The following request URL:
/calc/1/2/%2F
should produce the following plain text output:
1 / 2 = 0.5
Note
As part of a URL, the division operator (/) is URL-encoded (%2F).After testing the API using the Test Invoke in the API Gateway console, you must deploy the API to make it public available. If you update the API, such as adding, modifying or deleting a resource or method, updating any data mapping, you must redeploy the API to make the new features or updates available.