DEV Community

Cover image for Two ways to directly integrate AWS Lambda function with Amazon API Gateway
Wojciech Matuszewski for AWS Community Builders

Posted on • Edited on

Two ways to directly integrate AWS Lambda function with Amazon API Gateway

Since the inception of the concept of "serverless", the combination of Amazon API Gateway and AWS Lambda function has become one of the most popular serverless patterns on AWS.

With the advent of deployment frameworks like AWS CDK or AWS SAM, it has never been easier, using IaC, to deploy this pattern for the world to see.

As with many things in programming and computer science, there are often multiple ways to do something. The integration of API Gateway with the Amazon Lambda function is no different – one could use the proxy and non-proxy integration type.

This blog post will discuss the difference between the proxy and non-proxy integration and in which situations you might want to use a given integration method.

The proxy and non-proxy are used here only in the context of the integration type and have nothing to do with service proxies or proxy resources.

The proxy integration

I would argue that the proxy integration type is the most commonly deployed one. Partly because, to my knowledge, it is the default one that most of the deployment frameworks utilize, and partly because it is relatively light on the configuration side of things.

The following is a simplified diagram of the API Gateway integration with the AWS Lambda function via the proxy type.

Note that all the diagrams in this article omit concepts related to authorization and authentication as they are not relevant to the ideas presented in the text.

_proxy_ integration type

  • With the proxy integration, you lose the ability to perform data manipulation directly via the API Gateway mapping templates.

    • Since you cannot use the mapping templates and the VTL, your function code might be a bit more complex than the non-proxy counterpart.
  • Very light on the configuration side of things. The IaC declaration is relatively easy to maintain.

  • You still able to take advantage of the API Gateway validation models. A feature that, in my humble opinion, is underutilized.

Before using the API Gateway validation models, consider reading this article as it surfaces some of the issues you might encounter.

For completeness' sake, here is the minimal configuration required to integrate the API Gateway with an AWS Lambda function using AWS CDK and TypeScript.

const api = new aws_apigateway.RestApi(this, "API", {});

const handler = new aws_lambda_nodejs.NodejsFunction(this, "Handler", {
  entry: join(__dirname, "./handler.ts")
});

api.root.addMethod("GET", new aws_apigateway.LambdaIntegration(handler));
Enter fullscreen mode Exit fullscreen mode

Pretty minimal, right? Now, onto the non-proxy integration type.

The non-proxy integration type

It took me a while to familiarize myself with some of the options the API Gateway REST API exposes. Looking back, I've allocated a sizeable portion of that time to understand how one could utilize the mapping templates and the non-proxy integration in the real world. There are a LOT of knobs one could tweak in this type of integration.

_non-proxy_ integration

  • When using the non-proxy integration type, you have to specify the response mapping template. If you do not, the API Gateway will fail with "Internal Server Error".

  • When writing API Gateway mapping templates you do NOT have the ability to use features that you might have used in AWS AppSync resolver templates. You should consider the VTL in API Gateway and VTL in AppSync resolvers as two separate entities.

Here is the most minimal AWS CDK code snippet to declare an API Gateway route backed by non-proxy integration I could come up with.

const api = new aws_apigateway.RestApi(this, "API2", {});

const handler = new aws_lambda_nodejs.NodejsFunction(this, "Handler", {
  entry: join(__dirname, "./handler.ts")
});

const nonProxyIntegrationResource = api.root.addResource("non-proxy");

nonProxyIntegrationResource.addMethod(
  "GET",
  new aws_apigateway.LambdaIntegration(handler, {
    proxy: false,
    /** Optional */
    requestTemplates: {
      /**
       * This is what the Lambda function is invoked with.
       */
      "application/json": '{"foo": "bar"}'
    },
    /**
     * Required
     */
    integrationResponses: [
      {
        statusCode: "200",
        responseTemplates: {
          "application/json": "$input.json('$.body')"
        }
      }
    ]
  }),
  {
    /**
     * Required
     */
    methodResponses: [
      {
        statusCode: "200"
      }
    ]
  }
);
Enter fullscreen mode Exit fullscreen mode

My recommendation

  • When integrating API Gateway with AWS Lambda function, consider using the proxy integration as the default integration type, especially if you are new to the service or are working with a team yet to familiarize themselves with API Gateway and AWS Lambda.

  • Consider using the non-proxy integration for massaging the input data and precomputing given properties. Consult with your team on this one. It all depends on the use case.

  • Take some time to learn the non-proxy integration as the notion of mapping templates and other closely related settings are what drives the API Gateway direct service integrations.

Closing worlds

I find it very valuable to dive deep into a given AWS service, especially when I'm unfamiliar with a particular way of configuring it – I've mainly used the proxy integration throughout, albeit not that long, my career. I encourage you to do a similar and write about your findings. This way, the whole community can benefit and learn together!

For more serverless content, consider following me on Twitter - @wm_matuszewski

And as always, thank you for your precious time.

Top comments (0)