Terraform aws_api_gateway_resource in Practice

Terraform codifies Amazon API Gateway resources so that REST API paths, methods, and integrations are reproducible and versioned. The aws_api_gateway_resource resource represents a path within a REST API and serves as the anchor for methods and integrations. In a typical CRUD pattern the resource is referenced by ID when methods and proxy integrations are declared, and the deployment object captures a versioned snapshot of the whole API.

Resource actions in Terraform plans are indicated with symbols. Create operations are shown with +. Terraform will perform the following actions:

+ create

A deployment example from a CRUD setup shows:

```

awsapigatewaydeployment.cruddeployment will be created

  • resource "awsapigatewaydeployment" "cruddeployment" {
  • created_date = (known after apply)
  • execution_arn = (known after apply)
  • id = (known after apply)
  • invoke_url = (known after apply)
  • restapiid = (known after apply)
    }
    ```

One for each of the resources we are going to deploy.

REST API Resource and Path Modeling

The aws_api_gateway_resource is the path element. It is identified by the parent REST API and the path part. Methods are attached to the resource by referencing its ID.

A common pattern creates a resource named items and then attaches GET, PUT and DELETE methods:

```
awsapigatewayresource.items.id
http
method = "PUT"
authorization = "NONE"
}

DELETE method

resource "awsapigatewaymethod" "delete" {
rest
apiid = awsapigatewayrestapi.crudapi.id
resourceid = awsapigatewayresource.items.id
http_method = "DELETE"
authorization = "NONE"
}
```

For each we pass in the API Gateway ID, the items resource ID and the method to be used (GET, PUT etc).

For each of these methods, we then need to set up a Proxy to route calls to the Lambda using the aws_api_gateway_integration resource type:

```

Lambda integration for GET

resource "awsapigatewayintegration" "lambdaget" {
restapiid = awsapigatewayrestapi.crudapi.id
resource
id = awsapigatewayresource.items.id
http
method = awsapigatewaymethod.get.httpmethod
integrationhttpmethod = "POST"
type = "AWSPROXY"
uri = aws
lambdafunction.crudlambda.invoke_arn
}

Lambda integration for POST

resource "awsapigatewayintegration" "lambdapost" {
restapiid = awsapigatewayrestapi.crudapi.id
resource
id = awsapigatewayresource.items.id
http
method = awsapigatewaymethod.post.httpmethod
integrationhttpmethod = "POST"
type = "AWSPROXY"
uri = aws
lambdafunction.crudlambda.invoke_arn
}

Lambda integration for PUT

resource "awsapigatewayintegration" "lambdaput" {
restapiid = awsapigatewayrestapi.crudapi.id
resource
id = awsapigatewayresource.items.id
http
method =
```

The integration references the same Lambda but can be routed to different Lambda functions per method.

API Gateway Deployments

Deployments capture an immutable version of the API. The aws_api_gateway_deployment resource is created per stage or release and exposes known-after-apply attributes such as created_date, execution_arn, id, invoke_url, and rest_api_id.

The plan output shows the resource will be created with those attributes known after apply. Deployments are the mechanism by which changes to resources, methods, and integrations become live at a stage.

Terraform Modules for API Gateway v2

The serverless.tf framework simplifies HTTP and WebSocket API Gateway v2 provisioning via a module that creates API Gateway v2 resources with HTTP/Websocket capabilities.

A module declaration example:

```
module "apigateway" {
source = "terraform-aws-modules/apigateway-v2/aws"
name = "dev-http"
description = "My awesome HTTP API Gateway"
protocol
type = "HTTP"
corsconfiguration = {
allow
headers = ["content-type", "x-amz-date", "authorization", "x-api-key", "x-amz-security-token", "x-amz-user-agent"]
allowmethods = ["*"]
allow
origins = ["*"]
}

Custom domain

domain_name = "terraform-aws-modules.modules.tf"

Access logs

stageaccesslogsettings = {
create
loggroup = true
log
groupretentionin_days = 7
format = jsonencode({
context = {
domainName = "$context.domainName"
integrationErrorMessage = "$context.integrationErrorMessage"
protocol = "$context.protocol"
requestId = "$context.requestId"
requestTime = "$context.requestTime"
responseLength = "$context.responseLength"
routeKey = "$context.routeKey"
stage = "$context.stage"
status = "$context.status"
error = {
message = "$context.error.message"
responseType = "$context.error.responseType"
}
identity = {
sourceIP = "$context.identity.sourceIp"
}
integration = {
error = "$context.integration.error"
integrationStatus = "$context.integration.integrationStatus"
}
}
})
}

Authorizer(s)

authorizers = {
"azure" = {
authorizertype = "JWT"
identity
sources = ["$request.header.Authorization"]
name
```

The module supports combinations such as:

  • Complete HTTP - Create API Gateway, authorizer, domain name, stage and other resources in various combinations
  • HTTP with VPC Link - Create API Gateway with VPC link and integration with resources in VPC (eg. ALB)
  • Websocket - Create Websocket API

Module Requirements and Resources

Provider requirements for the module are specified as:

Name Version
terraform >= 1.5.7
aws >= 6.28
Name Version
aws >= 6.28

Module dependencies:

Name Source Version
acm terraform-aws-modules/acm/aws 6.2.0

Resources created by the module include:

Name Type
awsapigatewayv2api.this resource
awsapigatewayv2api_mapping.this resource
awsapigatewayv2authorizer.this resource
awsapigatewayv2deployment.this resource
awsapigatewayv2domain_name.this resource
awsapigatewayv2integration.this resource
awsapigatewayv2integration_response.this resource
awsapigatewayv2route.this resource
awsapigatewayv2route_response.this resource
awsapigatewayv2stage.this resource
awsapigatewayv2vpc_link.this resource
awscloudwatchlog_group.this resource
awsroute53record.this resource
awsroute53zone.this data source

A configurable parameter example:

Name Description Type Default Required
apikeyselection_expression An API key selection expression. Valid values: $context.authorizer.usageIdentifierKey, $request.header.x-api-key. Defaults to $request.header.x-api-key

CloudPosse API Gateway Module for REST APIs

Terraform module to provision API Gateway resources.

The root module creates an API Gateway REST API along with configuring tracing, logging, and metrics.

The module also consists of the following submodules:

  • account-settings - to provision account-level settings for logging and metrics for API Gateway

Tip

A set of modules for configuring an API Gateway

Setup the account-level settings for logging and metrics for API Gateway:

```
module "apigatewayaccount_settings" {
source = "cloudposse/api-gateway/aws//modules/account-settings"

version = "x.x.x"

context = module.this.context
}
```

Important

In Cloud Posse's examples, we avoid pinning modules to specific versions to prevent discrepancies between the documentation and the latest released versions. However, for your own projects, we strongly advise pinning each module to the exact version you're using. This practice ensures the stability of your infrastructure

Lambda and API Gateway Integration in Practice

API Gateway is an AWS managed service that allows you to create and manage HTTP or WebSocket APIs.

A HashiCorp tutorial workflow shows a Terraform apply result:

! 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:

aws_lambda_function.hello_world configures the Lambda function to use the bucket object containing your function code

Apply output after adding API Gateway integration:

```
. Respond to the confirmation prompt with a yes
.
$ terraform apply

...

Apply complete! Resources: 4 added, 0 changed, 0 destroyed.
Outputs:
functionname = "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.

Conclusion

The aws_api_gateway_resource remains the central path construct in REST API Terraform configurations. It ties together methods and integrations, and its ID is the reference point for aws_api_gateway_method and aws_api_gateway_integration resources. In practice the resource is created once per path segment, methods are attached by resource_id, and deployments lock the configuration for a stage.

Modules for API Gateway v2 abstract away the many aws_apigatewayv2_* resources needed for HTTP, WebSocket, custom domains, authorizers, VPC links and access logging, while CloudPosse modules provide account-level settings for logging and metrics for REST APIs. The HashiCorp tutorial demonstrates the end-to-end flow from Lambda packaging in S3 through IAM roles and CloudWatch log groups to a working invoke, confirming that Terraform can model both the compute and the API surface as a single declarative plan.

Sources

  1. https://dev.to/aws-builders/deploying-amazon-api-gateway-and-lambda-with-terraform-1i2o
  2. https://github.com/terraform-aws-modules/terraform-aws-apigateway-v2
  3. https://github.com/cloudposse/terraform-aws-api-gateway
  4. https://developer.hashicorp.com/terraform/tutorials/aws/lambda-api-gateway

Related Posts