A RetroSearch Logo

Home - News ( United States | United Kingdom | Italy | Germany ) - Football scores

Search Query:

Showing content from https://developer.hashicorp.com/terraform/tutorials/aws/lambda-api-gateway below:

Deploy serverless applications with AWS Lambda and API Gateway | Terraform

Serverless computing is a cloud computing model in which a cloud provider allocates compute resources on demand. This contrasts with traditional cloud computing where the user is responsible for directly managing virtual servers.

Most serverless applications use Functions as a Service (FaaS) to provide application logic, along with specialized services for additional capabilities such as routing HTTP requests, message queuing, and data storage.

In this tutorial, you will deploy a NodeJS function to AWS Lambda, and then expose that function to the Internet using Amazon API Gateway.

You can complete this tutorial using the same workflow with either Terraform Community Edition or HCP Terraform. HCP Terraform is a platform that you can use to manage and execute your Terraform projects. It includes features like remote state and execution, structured plan output, workspace resource summaries, and more.

Select the Terraform Community Edition tab to complete this tutorial using Terraform Community Edition.

Warning

Some of the infrastructure in this tutorial does not qualify for the AWS free tier. Destroy the infrastructure at the end of the guide to avoid unnecessary charges. We are not responsible for any charges that you incur.

Clone the Learn Terraform Lambda and API Gateway GitHub repository for this tutorial.

$ git clone https://github.com/hashicorp-education/learn-terraform-lambda-api-gateway

Change to the repository directory.

$ cd learn-terraform-lambda-api-gateway

Review the configuration in main.tf. It defines the AWS provider you will use for this tutorial and an S3 bucket which will store your Lambda function.

Set the TF_CLOUD_ORGANIZATION environment variable to your HCP Terraform organization name. This will configure your HCP Terraform integration.

$ export TF_CLOUD_ORGANIZATION=

Initialize your configuration. Terraform will automatically create the learn-terraform-lambda-api-gateway workspace in your HCP Terraform organization.

$ terraform init
Initializing HCP Terraform...
Initializing provider plugins...
- Reusing previous version of hashicorp/aws from the dependency lock file
- Reusing previous version of hashicorp/random from the dependency lock file
- Reusing previous version of hashicorp/archive from the dependency lock file
- Using previously-installed hashicorp/aws v5.38.0
- Using previously-installed hashicorp/random v3.6.0
- Using previously-installed hashicorp/archive v2.4.2

HCP Terraform has been successfully initialized!

You may now begin working with HCP Terraform. Try running "terraform plan" to
see any changes that are required for your infrastructure.

If you ever set or change modules or Terraform Settings, run "terraform init"
again to reinitialize your working directory.

Note: This tutorial assumes that you are using a tutorial-specific HCP Terraform organization with a global variable set of your AWS credentials. Review the Create a Credential Variable Set for detailed guidance. If you are using a scoped variable set, assign it to your new workspace now.

Open your terraform.tf file and comment out the cloud block that configures the HCP Terraform integration.

terraform.tf

terraform {
  /*
  cloud {
    workspaces {
      name = "learn-terraform-lambda-api-gateway"
    }
  }
  */

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.38.0"
    }
##...
  }
}

Initialize this configuration.

$ terraform init
Initializing the backend...
##...
Terraform has been successfully initialized!
You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.
If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.

Apply the configuration to create your S3 bucket. Respond to the confirmation prompt with a yes.

$ terraform apply
## ...

Apply complete! Resources: 2 added, 0 changed, 0 destroyed.

Outputs:

lambda_bucket_name = "learn-terraform-functions-formally-cheaply-frank-mullet"

To deploy an AWS Lambda function, you must package it in an archive containing the function source code and any dependencies.

The way you build the function code and dependencies will depend on the language and frameworks you choose. In this tutorial, you will deploy the NodeJS function defined in the Git repository you cloned earlier.

Review the function code in hello-world/hello.js.

hello-world/hello.js

module.exports.handler = async (event) => {
  console.log('Event: ', event);
  let responseMessage = 'Hello, World!';

  return {
    statusCode: 200,
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      message: responseMessage,
    }),
  }
}

This function takes an incoming event object from Lambda and logs it to the console. Then it returns an object which API Gateway will use to generate an HTTP response.

Add the following configuration to main.tf to package and copy this function to your S3 bucket.

main.tf

data "archive_file" "lambda_hello_world" {
  type = "zip"

  source_dir  = "${path.module}/hello-world"
  output_path = "${path.module}/hello-world.zip"
}

resource "aws_s3_object" "lambda_hello_world" {
  bucket = aws_s3_bucket.lambda_bucket.id

  key    = "hello-world.zip"
  source = data.archive_file.lambda_hello_world.output_path

  etag = filemd5(data.archive_file.lambda_hello_world.output_path)
}

This configuration uses the archive_file data source to generate a zip archive and an aws_s3_object resource to upload the archive to your S3 bucket.

Create the bucket object now. Respond to the confirmation prompt with a yes.

$ terraform apply
## ...

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

Outputs:

lambda_bucket_name = "learn-terraform-functions-formally-cheaply-frank-mullet"

Once Terraform deploys your function to S3, use the AWS CLI to inspect the contents of the S3 bucket.

$ aws s3 ls $(terraform output -raw lambda_bucket_name)
2021-07-08 13:49:46        353 hello-world.zip

Add the following to main.tf to define your Lambda function and related resources.

main.tf

resource "aws_lambda_function" "hello_world" {
  function_name = "HelloWorld"

  s3_bucket = aws_s3_bucket.lambda_bucket.id
  s3_key    = aws_s3_object.lambda_hello_world.key

  runtime = "nodejs20.x"
  handler = "hello.handler"

  source_code_hash = data.archive_file.lambda_hello_world.output_base64sha256

  role = aws_iam_role.lambda_exec.arn
}

resource "aws_cloudwatch_log_group" "hello_world" {
  name = "/aws/lambda/${aws_lambda_function.hello_world.function_name}"

  retention_in_days = 30
}

resource "aws_iam_role" "lambda_exec" {
  name = "serverless_lambda"

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

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

This configuration defines four resources:

Add the following to outputs.tf to create an output value for your Lambda function's name.

outputs.tf

output "function_name" {
  description = "Name of the Lambda function."

  value = aws_lambda_function.hello_world.function_name
}

Apply this configuration to create your Lambda function and associated resources. Respond to the confirmation prompt with a yes.

$ terraform apply
## ...

Apply complete! Resources: 4 added, 0 changed, 0 destroyed.

Outputs:

function_name = "HelloWorld"
lambda_bucket_name = "learn-terraform-functions-formally-cheaply-frank-mullet"

Once Terraform creates the function, invoke it using the AWS CLI.

$ aws lambda invoke --region=us-east-1 --function-name=$(terraform output -raw function_name) response.json
{
    "StatusCode": 200,
    "ExecutedVersion": "$LATEST"
}

Check the contents of response.json to confirm that the function is working as expected.

$ cat response.json
{"statusCode":200,"headers":{"Content-Type":"application/json"},"body":"{\"message\":\"Hello, World!\"}"}

This response matches the object returned by the handler function in hello-world/hello.js.

You can review your function in the AWS Lambda Console.

API Gateway is an AWS managed service that allows you to create and manage HTTP or WebSocket APIs. It supports integration with AWS Lambda functions, allowing you to implement an HTTP API using Lambda functions to handle and respond to HTTP requests.

Add the following to main.tf to configure an API Gateway.

main.tf

resource "aws_apigatewayv2_api" "lambda" {
  name          = "serverless_lambda_gw"
  protocol_type = "HTTP"
}

resource "aws_apigatewayv2_stage" "lambda" {
  api_id = aws_apigatewayv2_api.lambda.id

  name        = "serverless_lambda_stage"
  auto_deploy = true

  access_log_settings {
    destination_arn = aws_cloudwatch_log_group.api_gw.arn

    format = jsonencode({
      requestId               = "$context.requestId"
      sourceIp                = "$context.identity.sourceIp"
      requestTime             = "$context.requestTime"
      protocol                = "$context.protocol"
      httpMethod              = "$context.httpMethod"
      resourcePath            = "$context.resourcePath"
      routeKey                = "$context.routeKey"
      status                  = "$context.status"
      responseLength          = "$context.responseLength"
      integrationErrorMessage = "$context.integrationErrorMessage"
      }
    )
  }
}

resource "aws_apigatewayv2_integration" "hello_world" {
  api_id = aws_apigatewayv2_api.lambda.id

  integration_uri    = aws_lambda_function.hello_world.invoke_arn
  integration_type   = "AWS_PROXY"
  integration_method = "POST"
}

resource "aws_apigatewayv2_route" "hello_world" {
  api_id = aws_apigatewayv2_api.lambda.id

  route_key = "GET /hello"
  target    = "integrations/${aws_apigatewayv2_integration.hello_world.id}"
}

resource "aws_cloudwatch_log_group" "api_gw" {
  name = "/aws/api_gw/${aws_apigatewayv2_api.lambda.name}"

  retention_in_days = 30
}

resource "aws_lambda_permission" "api_gw" {
  statement_id  = "AllowExecutionFromAPIGateway"
  action        = "lambda:InvokeFunction"
  function_name = aws_lambda_function.hello_world.function_name
  principal     = "apigateway.amazonaws.com"

  source_arn = "${aws_apigatewayv2_api.lambda.execution_arn}/*/*"
}

This configuration defines four API Gateway resources, and two supplemental resources:

The API Gateway stage will publish your API to a URL managed by AWS.

Add an output value for this URL to outputs.tf.

outputs.tf

output "base_url" {
  description = "Base URL for API Gateway stage."

  value = aws_apigatewayv2_stage.lambda.invoke_url
}

Apply your configuration to create the API Gateway and other resources. Respond to the confirmation prompt with a yes.

$ terraform apply
## ...

Apply complete! Resources: 6 added, 0 changed, 0 destroyed.

Outputs:

base_url = "https://mxg7cq38p4.execute-api.us-east-1.amazonaws.com/serverless_lambda_stage"
function_name = "HelloWorld"
lambda_bucket_name = "learn-terraform-functions-formally-cheaply-frank-mullet"

Now, send a request to API Gateway to invoke the Lambda function. The endpoint consists of the base_url output value and the /hello path, which do you defined as the route_key.

$ curl "$(terraform output -raw base_url)/hello"
{"message":"Hello, World!"} 

When you call Lambda functions via API Gateway's proxy integration, API Gateway passes the request information to your function via the event object. You can use information about the request in your function code.

Now, use an HTTP query parameter in your function.

In hello-world/hello.js, add an if statement to replace the responseMessage if the request includes a Name query parameter.

hello-world/hello.js

module.exports.handler = async (event) => {
  console.log('Event: ', event)
  let responseMessage = 'Hello, World!';

  if (event.queryStringParameters && event.queryStringParameters['Name']) {
    responseMessage = 'Hello, ' + event.queryStringParameters['Name'] + '!';
  }

  return {
    statusCode: 200,
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      message: responseMessage,
    }),
  }
}

Apply this change now.

Since your source code changed, the computed etag and source_code_hash values have changed as well. Terraform will update your S3 bucket object and Lambda function.

Respond to the confirmation prompt with a yes.

$ terraform apply
## ...

Terraform will perform the following actions:

  # aws_lambda_function.hello_world will be updated in-place
  ~ resource "aws_lambda_function" "hello_world" {
        id                             = "HelloWorld"
      ~ last_modified                  = "2021-07-12T15:00:40.113+0000" -> (known after apply)
      ~ source_code_hash               = "ifMwKWStaDMUDQ3gh68yJzsWNPRfXHfpwMMDJcE1ymA=" -> "1esYQSK1oTfV84+KmDSwhVTBAy8eX6F6uBKLvNsf8AY="
        tags                           = {}
        # (18 unchanged attributes hidden)

        # (1 unchanged block hidden)
    }

  # aws_s3_object.lambda_hello_world will be updated in-place
  ~ resource "aws_s3_object" "lambda_hello_world" {
      ~ etag               = "ba1ce6b2aa28971920a6c2b8272fe7c6" -> "adb572ecc1b4f3eda7f497aad0bec527"
        id                 = "hello-world.zip"
        tags               = {}
      + version_id         = (known after apply)
        # (10 unchanged attributes hidden)
    }

Plan: 0 to add, 2 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

aws_s3_object.lambda_hello_world: Modifying... [id=hello-world.zip]
aws_s3_object.lambda_hello_world: Modifications complete after 0s [id=hello-world.zip]
aws_lambda_function.hello_world: Modifying... [id=HelloWorld]
aws_lambda_function.hello_world: Still modifying... [id=HelloWorld, 10s elapsed]
aws_lambda_function.hello_world: Modifications complete after 17s [id=HelloWorld]

Apply complete! Resources: 0 added, 2 changed, 0 destroyed.

Outputs:

base_url = "https://iz85oarz9l.execute-api.us-east-1.amazonaws.com/serverless_lambda_stage"
function_name = "HelloWorld"
lambda_bucket_name = "learn-terraform-functions-quietly-severely-crucial-gnu"

Now, send another request to your function, including the Name query parameter.

$ curl "$(terraform output -raw base_url)/hello?Name=Terraform"
{"message":"Hello, Terraform!"}

Before cleaning up your infrastructure, you can visit the AWS Lambda Console for your function to review the infrastructure you created in this tutorial.

Before moving on, clean up the infrastructure you created by running the terraform destroy command. Remember to confirm the operation with a yes.

$ terraform destroy
##...
Plan: 0 to add, 0 to change, 14 to destroy.

Changes to Outputs:
  - base_url           = "https://1q6qs02fjc.execute-api.us-east-1.amazonaws.com/serverless_lambda_stage" -> null
  - function_name      = "HelloWorld-rs" -> null
  - lambda_bucket_name = "learn-terraform-functions-reasonably-highly-firm-honeybee" -> null

Do you really want to destroy all resources in workspace "learn-terraform-lambda-api-gateway"?
  Terraform will destroy all your managed infrastructure, as shown above.
  There is no undo. Only 'yes' will be accepted to confirm.

  Enter a value: yes
##...
Apply complete! Resources: 0 added, 0 changed, 14 destroyed.

If you used HCP Terraform for this tutorial, after destroying your resources, delete the learn-terraform-lambda-api-gateway workspace from your HCP Terraform organization.

In this tutorial, you created and updated an AWS Lambda function with an API Gateway integration. These components are essential parts of most serverless applications.

Review the following resources to learn more about Terraform and AWS:


RetroSearch is an open source project built by @garambo | Open a GitHub Issue

Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo

HTML: 3.2 | Encoding: UTF-8 | Version: 0.7.4