Terraform AWS API Gateway Integration Resource Deep Dive

API Gateway integration is the connective tissue between an API Gateway front door and the backend service that actually fulfills requests. In Terraform, the aws_api_gateway_integration resource defines how a method on a resource maps to an upstream integration, including protocol type, URI, credentials, request parameters, and response handling. Getting the integration right determines latency, security, cost, and observability of the entire API surface.

What the Integration Resource Controls

An integration resource in AWS API Gateway REST APIs does not create a method. It attaches to an existing aws_api_gateway_method and describes where the request should be forwarded and how the response should be transformed.

Core attributes that appear in production examples include:

  • rest_api_id - the REST API identifier
  • resource_id - the API resource identifier
  • http_method - the method HTTP verb
  • type - the integration type
  • uri - the integration endpoint
  • credentials - IAM role ARN for AWS service integrations
  • integration_http_method - the HTTP verb used on the integration

The resource works in concert with aws_api_gateway_method, aws_api_gateway_resource, aws_api_gateway_deployment, and aws_api_gateway_stage. Deployments are commonly triggered by changes to the OpenAPI specification or by a hash of the spec to avoid manual redeploys.

OpenAPI Specification Driven Deployments

A production-ready Terraform project that deploys API Gateway using OpenAPI specifications separates concerns into three layers.

OpenAPI Specification Layer: A YAML file containing all API route definitions, HTTP methods, request/response schemas, and AWS-specific integration extensions. This file serves as both the API definition and documentation source.

Infrastructure Module: Reusable Terraform code that creates the API Gateway REST API, deployment, and stage resources. The module imports the OpenAPI specification and configures automatic redeployment using SHA1 hash triggers.

Environment Configuration: Environment-specific settings that reference the infrastructure module with appropriate parameters

This approach offers automatic documentation, version control for API changes, and seamless integration with AWS API Gateway. The solution includes automatic redeployment triggers when API definitions change, multi-environment support, and proper state management.

Backend state is typically stored in S3. Configuration edits are made to backend.hcl with your S3 bucket details:

bucket = "<your-terraform-state-bucket>" key = "api-gateway-openapi/dev/terraform.tfstate" region = "us-east-1"

Initialize Terraform with the backend configuration:

terraform init -backend-config=backend.hcl

This command downloads the AWS provider, configures the S3 backend for state storage, and initializes the infrastructure module.

Plan and apply follow standard workflows:

terraform plan -out=tfplan terraform apply "tfplan"

Expected output shows the three core resources:

  • module.apigateway.awsapigatewaydeployment.deploy will be created
  • module.apigateway.awsapigatewayrest_api.api will be created
  • module.apigateway.awsapigatewaystage.stage will be created

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

After successful deployment Terraform displays the API endpoint:

Outputs: api_url = "https://abc123def4.execute-api.us-east-1.amazonaws.com/dev"

Testing endpoints uses the printed URL:

curl https://<api-id>.execute-api.us-east-1.amazonaws.com/dev/users

Expected response:

{ "message": "GET /users - Request received successfully", "users": ["user1", "user2"] }

AWS Service Integration Example

The Terraform AWS provider includes examples for integrating API Gateway with AWS services directly. The S3 integration example creates an API Gateway REST API that proxies to S3 using an AWS integration type.

Provider configuration is set with a region variable:

provider "aws" { region = var.aws_region }

IAM is required for service integrations. A policy granting S3 actions is created:

resource "aws_iam_policy" "s3_policy" { name = "s3-policy" description = "Policy for allowing all S3 Actions" policy = <<EOF { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "s3:*", "Resource": "*" } ] } EOF }

The API Gateway role assumes the apigateway.amazonaws.com service principal:

resource "aws_iam_role" "s3_api_gateway_role" { name = "s3-api-gateway-role" assume_role_policy = <<EOF { "Version": "2012-10-17", "Statement": [ { "Sid": "", "Effect": "Allow", "Principal": { "Service": "apigateway.amazonaws.com" }, "Action": "sts:AssumeRole" } ] } EOF }

The role is attached to the S3 policy:

resource "aws_iam_role_policy_attachment" "s3_policy_attach" { role = aws_iam_role.s3_api_gateway_role.name policy_arn = aws_iam_policy.s3_policy.arn }

The REST API and resources are defined:

resource "aws_api_gateway_rest_api" "MyS3" { name = "MyS3" description = "API for S3 Integration" }

Resources model path parameters:

resource "aws_api_gateway_resource" "Folder" { rest_api_id = aws_api_gateway_rest_api.MyS3.id parent_id = aws_api_gateway_rest_api.MyS3.root_resource_id path_part = "{folder}" } resource "aws_api_gateway_resource" "Item" { rest_api_id = aws_api_gateway_rest_api.MyS3.id parent_id = aws_api_gateway_resource.Folder.id path_part = "{item}" }

The method is created with AWS_IAM authorization:

resource "aws_api_gateway_method" "GetBuckets" { rest_api_id = aws_api_gateway_rest_api.MyS3.id resource_id = aws_api_gateway_rest_api.MyS3.root_resource_id http_method = "GET" authorization = "AWS_IAM" }

The integration connects the method to S3:

resource "aws_api_gateway_integration" "S3Integration" { rest_api_id = aws_api_gateway_rest_api.MyS3.id resource_id = aws_api_gateway_rest_api.MyS3.root_resource_id http_method = aws_api_gateway_method.GetBuckets.http_method integration_http_method = "GET" type = "AWS" uri = "arn:aws:apigateway:${var.aws_region}:s3:path//" credentials = aws_iam_role.s3_api_gateway_role.arn }

Method responses define the contract for clients:

resource "aws_api_gateway_method_response" "Status200" { rest_api_id = aws_api_gateway_rest_api.MyS3.id resource_id = aws_api_gateway_rest_api.MyS3.root_resource_id http_method = aws_api_gateway_method.GetBuckets.http_method status_code = "200" response_parameters = { "method.response.header.Timestamp" = true "method.response.header.Content-Length" = true "method.response.header.Content-Type" = true } response_models = { "application/json" = "Empty" } }

Integration responses would map the backend response to the method response, handling status codes, headers, and transformation templates.

Integration Types and Attributes

Different backend targets require different integration configurations. The resource supports several types.

  • AWS - direct integration with AWS services via service name and path
  • AWS_PROXY - proxy integration for AWS Lambda
  • HTTP - integration with any HTTP endpoint
  • HTTP_PROXY - proxy pass-through for HTTP endpoints
  • MOCK - returns static responses without backend call

A comparison of common attributes is shown below.

| Attribute | Purpose | Example Value |
| restapiid | Links integration to API | awsapigatewayrestapi.MyS3.id |
| resourceid | Links integration to resource | awsapigatewayrestapi.MyS3.rootresourceid |
| http
method | API method verb | GET |
| type | Integration class | AWS |
| uri | Backend endpoint | arn:aws:apigateway:${var.awsregion}:s3:path// |
| credentials | IAM role ARN for AWS integration | aws
iamrole.s3apigatewayrole.arn |
| integrationhttpmethod | Verb used on backend | GET |

For Lambda integrations, tutorials show setting the provider and an S3 bucket which will store your Lambda function. The HCP Terraform workflow includes:

export TF_CLOUD_ORGANIZATION=

Initialize your configuration:

terraform init

Initializing HCP Terraform downloads provider plugins and creates the workspace.

Apply the configuration to create your S3 bucket and related resources before deploying the integration.

API Gateway V2 HTTP and WebSocket Considerations

Modern serverless architectures often use API Gateway v2 for HTTP APIs. The Terraform module for API Gateway v2 creates HTTP/Websocket capabilities.

Module configuration includes:

module "api_gateway" { source = "terraform-aws-modules/apigateway-v2/aws" name = "dev-http" description = "My awesome HTTP API Gateway" protocol_type = "HTTP" cors_configuration = { allow_headers = ["content-type", "x-amz-date", "authorization", "x-api-key", "x-amz-security-token", "x-amz-user-agent"] allow_methods = ["*"] allow_origins = ["*"] } }

Access logging can be configured per stage:

stage_access_log_settings = { create_log_group = true log_group_retention_in_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" } } }) }

Authorizers can be attached:

authorizers = { "azure" = { authorizer_type = "JWT" identity_sources = ["$request.header.Authorization"] name

Custom domain and certificate management are handled through the module inputs.

Deployment Planning and State

Terraform plans for API Gateway deployments show the resources that will be created. Typical output includes:

```
Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:

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.

State management is critical because API Gateway resources have implicit dependencies. The deployment resource must be recreated when methods, integrations, or resources change. Using a SHA1 hash of the OpenAPI spec as a trigger ensures deterministic redeploys.

Common Patterns and Pitfalls

  • Use explicit integrationhttpmethod. The S3 example includes it because of known provider behavior.
  • Set credentials for AWS integrations. Without a role with appropriate trust policy, requests fail with 500 errors.
  • Define method responses and integration responses separately for REST APIs. HTTP APIs handle responses implicitly.
  • Avoid hardcoding ARNs. Use variables for region and account.
  • Keep IAM policies least privilege. The example uses s3:* for demonstration.
  • Monitor stage access logs for integration errors and latency.

Conclusion

The aws_api_gateway_integration resource is the control point where API Gateway meets backend services. In Terraform, it is defined declaratively alongside the method, resource, and deployment graph. OpenAPI driven workflows add automatic documentation and versioned redeploys via SHA1 hash triggers. AWS service integrations require IAM roles with assume role policies and precise URI formatting. REST API integrations need explicit method and integration responses, while API Gateway v2 HTTP APIs provide simpler proxy semantics with built-in CORS and access logging. Consistent backend state, explicit dependency ordering, and tested plans reduce drift and make API Gateway integrations reliable across dev, staging, and production environments.

Sources

  1. blog.devops.dev
  2. github.com/hashicorp/terraform-provider-aws
  3. developer.hashicorp.com
  4. github.com/terraform-aws-modules
  5. dev.to

Related Posts