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
httpmethod = "PUT"
authorization = "NONE"
}
DELETE method
resource "awsapigatewaymethod" "delete" {
restapiid = 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
resourceid = awsapigatewayresource.items.id
httpmethod = awsapigatewaymethod.get.httpmethod
integrationhttpmethod = "POST"
type = "AWSPROXY"
uri = awslambdafunction.crudlambda.invoke_arn
}
Lambda integration for POST
resource "awsapigatewayintegration" "lambdapost" {
restapiid = awsapigatewayrestapi.crudapi.id
resourceid = awsapigatewayresource.items.id
httpmethod = awsapigatewaymethod.post.httpmethod
integrationhttpmethod = "POST"
type = "AWSPROXY"
uri = awslambdafunction.crudlambda.invoke_arn
}
Lambda integration for PUT
resource "awsapigatewayintegration" "lambdaput" {
restapiid = awsapigatewayrestapi.crudapi.id
resourceid = awsapigatewayresource.items.id
httpmethod =
```
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"
protocoltype = "HTTP"
corsconfiguration = {
allowheaders = ["content-type", "x-amz-date", "authorization", "x-api-key", "x-amz-security-token", "x-amz-user-agent"]
allowmethods = ["*"]
alloworigins = ["*"]
}
Custom domain
domain_name = "terraform-aws-modules.modules.tf"
Access logs
stageaccesslogsettings = {
createloggroup = true
loggroupretentionin_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"
identitysources = ["$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"
lambdabucket_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.