What is Lambda Proxy Integration?

Note: This is the second article of the API Gateway and Lambda series, and for the basic introductions and setup refer to the first article ‘Exposing AWS Lambda functions with the API Gateway’

In some scenarios, your Lambda function might want to receive and set the HTTP level details to or from the API Gateway, and this is when you would want to enable Lambda proxy integration for your deployment. Lambda Proxy allows your Lambda functions to access the raw HTTP level request attributes.

Let’s continue from our last example and create the 02-lambda-proxy-integration function to be as follows. We will log the input event, and return a response which is JSON. However, note that now we have to create our response object with a JSON structure as shown below – with a “body” element. Optionally we can specify custom response code and headers as shown in the example. However, note that the ‘body‘ element must be a String.

exports.handler = async (event) => {
       console.log("Event: " + JSON.stringify(event));
       let response = {
              "isBase64Encoded": true,
              "statusCode": 200,
               "headers": {
                     "Custom-Response-Header": "some value"
               },
              "body": JSON.stringify({"message": "Successfully executed"})
       };
       return response;
};

Executing this function with the same request from our previous example, we see the following response.

curl -sD - -d '{ "name":"John", "age":31, "city":"New York" }' https://qaydahje3e.execute-api.us-east-1.amazonaws.com/dev/02-lambda-proxy-integration
HTTP/1.1 200 OK
Content-Type: application/json
..<additional headers removed for clarity>..
Custom-Response-Header: some value

{"message":"Successfully executed"}

The request ‘event’ object as seen in our output from the function log is as follows.

Thus for a basic Lambda function without proxy integration, the raw payload becomes the event, and the response becomes the body of the HTTP response.

However when Lambda proxy integration is enabled, the event includes the raw HTTP request details as can be seen below, and the response needs to be constructed with the status code, body, and optional response headers, etc as shown above. And, if you want to access say the HTTP path of the incoming request, you can access it via ‘event.requestContext.path’ and the incoming content-type HTTP header via ‘event.headers[‘Content-Type’]’ or request query parameters via ‘event.stringQueryParameters.name’ – which would not be possible if you did not have Lambda Proxy Integration enabled. Lambda Proxy Integration also allows you to access request query parameters, which you can access via ‘event.queryStringParameters.<parameter-name>’.

Accessing the payload

Assume you send a JSON request to a REST API as shown below. Let’s see how the payload can be accessed within the Lambda function.

curl -sD - -d '{ "name":"John", "age":31, "city":"New York" }' 'https://qaydahje3e.execute-api.us-east-1.amazonaws.com/dev/02-lambda-proxy-integration'

In a Lambda function without Proxy Integration, you can access the payload property ‘name’ as ‘event.name’ and the age as ‘event.age’ etc. However when Lambda Proxy Integration is enabled, you can only fetch the request HTTP payload as the ‘event.body’ and this would be a plain String, or a Base64 encoded String, based on the ‘event.isBase64Encoded’ property.

{
    "path": "/02-lambda-proxy-integration",
    "httpMethod": "POST",
    "headers": {
        ...
    },
    ...
    "body": "{ \"name\":\"John\", \"age\":31, \"city\":\"New York\" }",
    "isBase64Encoded": false
}

Lambda Proxy Integration with HTTP APIs?

In our last article, we introduced API Gateway HTTP APIs. With REST APIs we had to enable Lambda Proxy Integration to access the raw HTTP level attributes. However, with HTTP APIs these are made available by default!

Note that there are two versions for the payload formats called Format 2.0 and Format 1.0.  Format 2.0 doesn’t have multiValueHeaders or multiValueQueryStringParameters fields. Duplicate headers are combined with commas and included in the headers field. Duplicate query strings are combined with commas and included in the queryStringParameters field. Format 2.0 includes a new cookies field. All cookie headers in the request are combined with commas and added to the cookies field. In response to the client, each cookie becomes a set-cookie header. You can visit the official documentation at https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html to learn more about these versions.

Let’s try out a basic HTTP API integrated Lambda function as shown below. Note that we can send a response without having to worry about a response format with a ‘statusCode’ and ‘body’ as with REST APIs. The implementation processes the response of the Lambda function correctly. Note that there are subtle differences in getting the path or request headers between REST APIs and HTTP APIs. A significant point to note is that request headers are presented always in lower case within the ‘event’ object.

exports.handler = async (event) => {
  console.log("Event : " + JSON.stringify(event));
  console.log("Method : " + event.requestContext.http.method);
  console.log("Path : " + event.rawPath);
  console.log("Name : " + event.queryStringParameters.name);
  console.log("Age : " + event.queryStringParameters.age);
  console.log("X-Token : " + event.headers['x-token']); 
  console.log("Body : " + event.body);
  return {"message": "Successfully executed"};
};

Invoke it with a custom header and payload.

curl -sD - -H 'X-Token: 3456' -d '{ "name":"John", "age":31, "city":"New York" }' 'https://y07wvgwxe0.execute-api.us-east-1.amazonaws.com/04-basic-http-api?name=John&age=34'

You will see the ‘event’ object having a structure as follows. Note that the ‘event.body’ is a Base64 encoded String, as further indicated by the ‘isBase64Encoded’ property.

{
    "version": "2.0",
    "rawPath": "/04-basic-http-api",
    "rawQueryString": "name=John&age=34",
    "headers": {
        "content-type": "application/x-www-form-urlencoded",
        "x-token": "3456"
    },
    "queryStringParameters": {
        "age": "34",
        "name": "John"
    },
    "requestContext": {
        "http": {
            "method": "POST",
            "path": "/04-basic-http-api",
            ...
        },
        ...
    },
    "body": "eyAibmFtZSI6IkpvaG4iLCAiYWdlIjozMSwgImNpdHkiOiJOZXcgWW9yayIgfQ==",
    "isBase64Encoded": true
}

Next Steps

Continue to the ‘API Gateway and Lambda examples‘ to understand the more advanced scenarios with API Gateway and AWS Lambda