Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is the method response of an API gateway different when being created using terraform?

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..

enter image description here

But if I create the same API gateway using AWS console, the Method Response section displays something different:

enter image description here

Why does this happen?

The following steps are how I use AWS console to create the API gateway:

  1. Select Create Method under the resource. enter image description here

  2. Select POST method. enter image description here

  3. Select the desired options. enter image description here

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.

like image 236
Brian Avatar asked May 10 '19 05:05

Brian


People also ask

What is method response in API gateway?

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.

What is the role of the integration request in an API method in Amazon API gateway?

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).

When configuring a new API method in API gateway using the mock integration type which configuration setting requires no changes?

Hence, When configuring a new API method in API Gateway integration response configuration needs no changes.

What is Aws_api_gateway_integration?

Resource: aws_api_gateway_integration. Provides an HTTP Method Integration for an API Gateway Integration.


2 Answers

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.

like image 70
Thales Minussi Avatar answered Oct 09 '22 01:10

Thales Minussi


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!

enter image description here

Not very clear in terraform docs what this should look like, had to figure out myself after many attempts.

like image 22
babis21 Avatar answered Oct 09 '22 00:10

babis21