Automate REST API Management with Terraform: AWS API Gateway Proxy Integration and Lambda
Tags: terraform, aws, lambda, apigateway
Published: 2024-07-01 18:06:24

In my previous post, I talked about how to simplify REST API management with [AWS API Gateway Proxy Integration and Lambda](https://dev.to/sepiyush/simplify-rest-api-management-with-aws-api-gateway-proxy-integration-and-lambda-1j5j) using the AWS Console. In this blog, I will discuss how to achieve the same setup using Terraform.

### Overview

Using Terraform to manage your infrastructure as code (IaC) provides several advantages, such as version control, automation, and consistency across environments. The steps to integrate an API Gateway with Lambda using Terraform involve:

1. Creation of API Gateway.
2. Granting it `AllowAPIGatewayInvoke` permission to invoke the desired Lambda function.
3. Creating a proxy resource with the path `{proxy+}`.
4. Creating an `ANY` proxy method for the proxy resource.
5. Creating an API Stage.
6. Creating a deployment.

### Terraform Code Example

Here is the example Terraform code that includes the creation of a Lambda function and the necessary API Gateway configuration:

```hcl
# Lambda Function
resource "aws_lambda_function" "lambda" {
  function_name = var.lambda_function_name
  role          = aws_iam_role.lambda_role.arn
  filename      = "location/of/package.zip"
  handler       = "index.handler"
  runtime       = "nodejs20.x"
  memory_size   = 512
  timeout       = 10
}

#Grants API Gateway permission to invoke the Lambda function.
resource "aws_lambda_permission" "apigw" {
  statement_id  = "AllowAPIGatewayInvoke"
  action        = "lambda:InvokeFunction"
  function_name = aws_lambda_function.lambda.function_name
  principal     = "apigateway.amazonaws.com"
  source_arn    = "${aws_api_gateway_rest_api.api.execution_arn}/${var.stage}/*"
}

#Creates an IAM role with the necessary permissions 
resource "aws_iam_role" "lambda_role" {
  name = "lambda_role"

  assume_role_policy = jsonencode({
    Version = "2012-10-17",
    Statement = [
      {
        Action = "sts:AssumeRole",
        Effect = "Allow",
        Principal = {
          Service = "lambda.amazonaws.com"
        }
      }
    ]
  })
}

resource "aws_iam_role_policy_attachment" "lambda_policy" {
  role       = aws_iam_role.lambda_role.name
  policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
}

# API Gateway
resource "aws_api_gateway_rest_api" "api" {
  name = var.api_name
}

# Creates a proxy resource with the path `{proxy+}`.
resource "aws_api_gateway_resource" "proxy" {
  rest_api_id = aws_api_gateway_rest_api.api.id
  parent_id   = aws_api_gateway_rest_api.api.root_resource_id
  path_part   = "{proxy+}"
}

# Defines the `ANY` method for the proxy resource.
resource "aws_api_gateway_method" "proxy_method" {
  rest_api_id   = aws_api_gateway_rest_api.api.id
  resource_id   = aws_api_gateway_resource.proxy.id
  http_method   = "ANY"
  authorization = "NONE"
}

# Integrates proxy_method and proxy resource with each other
resource "aws_api_gateway_integration" "proxy_integration" {
  rest_api_id             = aws_api_gateway_rest_api.api.id
  resource_id             = aws_api_gateway_resource.proxy.id
  http_method             = aws_api_gateway_method.proxy_method.http_method
  type                    = "AWS_PROXY"
  integration_http_method = "POST"
  uri                     = aws_lambda_function.lambda.invoke_arn
}

resource "aws_api_gateway_deployment" "api_deployment" {
  depends_on = [
    aws_api_gateway_method.proxy_method,
    aws_api_gateway_integration.proxy_integration,
  ]
  rest_api_id = aws_api_gateway_rest_api.api.id
  lifecycle {
    create_before_destroy = true
  }
}

# Defines the deployment stage for the API Gateway.
resource "aws_api_gateway_stage" "api_stage" {
  stage_name    = var.stage
  rest_api_id   = aws_api_gateway_rest_api.api.id
  deployment_id = aws_api_gateway_deployment.api_deployment.id
}

data "aws_caller_identity" "current" {}

variable "api_name" {
  description = "The name of the API Gateway"
}

variable "stage" {
  description = "The deployment stage"
}

variable "lambda_function_name" {
  description = "The name of the Lambda function"
}

```

### Conclusion

Using Terraform to manage your API Gateway and Lambda integration provides a consistent and automated way to handle your infrastructure as code. By following the steps outlined in this blog, you can easily set up a REST API with AWS API Gateway Proxy Integration and Lambda, making your serverless application more manageable and scalable.

This approach not only simplifies the management of your routes but also ensures a more efficient and streamlined serverless architecture. By centralizing your API management with Terraform, you gain greater control and flexibility over your deployments.