I have the following terraform script which creates an API gateway that passes requests to a lambda function.
provider "aws" {
access_key = "${var.access_key}"
secret_key = "${var.secret_key}"
#
region = "${var.region}"
version = "~> 2.6"
}
resource "aws_api_gateway_rest_api" "MyDemoAPI" {
name = "MyDemoAPI"
description = "This is my API for demonstration purposes"
}
resource "aws_api_gateway_resource" "MyDemoResource" {
rest_api_id = "${aws_api_gateway_rest_api.MyDemoAPI.id}"
parent_id = "${aws_api_gateway_rest_api.MyDemoAPI.root_resource_id}"
path_part = "mydemoresource"
}
resource "aws_api_gateway_method" "MyDemoMethod" {
rest_api_id = "${aws_api_gateway_rest_api.MyDemoAPI.id}"
resource_id = "${aws_api_gateway_resource.MyDemoResource.id}"
http_method = "POST"
authorization = "NONE"
}
resource "aws_api_gateway_integration" "MyDemoIntegration" {
rest_api_id = "${aws_api_gateway_rest_api.MyDemoAPI.id}"
resource_id = "${aws_api_gateway_resource.MyDemoResource.id}"
http_method = "${aws_api_gateway_method.MyDemoMethod.http_method}"
integration_http_method = "POST"
type = "AWS_PROXY"
uri = "arn:aws:apigateway:ap-southeast-1:lambda:path/2015-03-31/functions/${aws_lambda_function.test_lambda_function.arn}/invocations"
content_handling = "CONVERT_TO_TEXT"
}
resource "aws_api_gateway_method_response" "200" {
rest_api_id = "${aws_api_gateway_rest_api.MyDemoAPI.id}"
resource_id = "${aws_api_gateway_resource.MyDemoResource.id}"
http_method = "${aws_api_gateway_method.MyDemoMethod.http_method}"
status_code = "200"
response_models {
"application/json" = "Empty"
}
}
resource "aws_lambda_function" "test_lambda_function" {
filename = "lambda.zip"
description = "test build api gateway and lambda function using terraform"
function_name = "test_lambda_function"
role = "arn:aws:iam::123456789123:role/my_labmda_role"
handler = "gateway.lambda_handler"
runtime = "python3.6"
memory_size = 128
timeout = 60
}
The Method Response
section of the API gateway resource display Select an integration response.
.
But if I create the same API gateway using AWS console, the Method Response
section displays something different:
Why does this happen?
The following steps are how I use AWS console to create the API gateway:
Select Create Method
under the resource.
Select POST
method.
Select the desired options.
I've tried creating the above resources manually first, then execute terraform apply
. Then terraform tells me that nothing needs to be changed.
terraform apply
aws_api_gateway_rest_api.MyDemoAPI: Refreshing state... (ID: 1qa34vs1k7)
aws_lambda_function.test_lambda_function: Refreshing state... (ID: test_lambda_function)
aws_api_gateway_resource.MyDemoResource: Refreshing state... (ID: 4xej81)
aws_api_gateway_method.MyDemoMethod: Refreshing state... (ID: agm-1qa34vs1k7-4xej81-POST)
aws_api_gateway_method_response.200: Refreshing state... (ID: agmr-1qa34vs1k7-4xej81-POST-200)
aws_api_gateway_integration.MyDemoIntegration: Refreshing state... (ID: agi-1qa34vs1k7-4xej81-POST)
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
This seems to mean that the manually built structure is the same as the structure built by terraform.
An API method response encapsulates the output of an API method request that the client will receive. The output data includes an HTTP status code, some headers, and possibly a body.
An integration request is an HTTP request that API Gateway submits to the backend, passing along the client-submitted request data, and transforming the data, if necessary. The HTTP method (or verb) and URI of the integration request are dictated by the backend (that is, the integration endpoint).
Hence, When configuring a new API method in API Gateway integration response configuration needs no changes.
Resource: aws_api_gateway_integration. Provides an HTTP Method Integration for an API Gateway Integration.
Because API Gateway is a complex AWS component and you can control pretty much everything on it (basically every single part of it is managed independently, giving you a lot of control over what you create but also making things harder to deal with).
See that it says "Select an Integration Response", but since your Terraform code didn't create one, it is therefore empty.
I had come across this very same problem a few weeks ago and I found the solution on Terraform's GitHub. I think Terraform should better document this as you're not the first one nor will you be the last to come up with this question. Well, at least we have this documented in StackOverflow now :)
Long story short, you need to add a aws_api_gateway_integration_response
terraform resource to your API Gateway.
resource "aws_api_gateway_integration_response" "MyDemoIntegrationResponse" {
rest_api_id = "${aws_api_gateway_rest_api.MyDemoAPI.id}"
resource_id = "${aws_api_gateway_resource.MyDemoResource.id}"
http_method = "${aws_api_gateway_method.MyDemoMethod.http_method}"
status_code = "${aws_api_gateway_method_response.200.status_code}"
response_templates = {
"application/json" = ""
}
}
If you can, however, I suggest you use a proper framework to hook events to your Lambda functions (like the Serverless Framework or AWS SAM) as it's very verbose and error prone to create them in Terraform.
Usually, I combine Terraform and Serverless Framework together: I use Terraform to create infrastructure resources - even if they are serverless - like DynamoDB tables, SQS queues, SNS topics, etc. and the Serverless Framework to create the Lambda functions and their corresponding events.
I had the same issue. What Thales suggested didn't work for me (using terraform 0.11.14 with AWS plugin 2.52.0).
Instead, I used api_gateway_method_response resource and set the response_models parameter as:
response_models = {
"application/json" = "Empty"
}
Then it showed me the default response that all other APIs that I created through the console show!
Not very clear in terraform docs what this should look like, had to figure out myself after many attempts.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With