AWS API Gateway - Invalid Method identifier

I’m creating a REST api gateway resource (not a terraform resource). This requires the creation of five different terraform resources:

  1. *aws_api_gateway_resource
  2. *aws_api_gateway_method
  3. *aws_api_gateway_integration
  4. *aws_api_gateway_integration_response
  5. *aws_api_gateway_method_response

This is the code I have for creating the resources via iterating over a map of objects:

# Resources and Method Response with Object Variables
resource "aws_api_gateway_resource" "resource" {
  for_each    = var.resources
  path_part   = each.key #apigw_path_parts
  rest_api_id = aws_api_gateway_rest_api.iddw.id
  parent_id   = aws_api_gateway_rest_api.iddw.root_resource_id
}

resource "aws_api_gateway_method" "method" {
  for_each           = var.resources
  rest_api_id        = aws_api_gateway_rest_api.iddw.id
  resource_id        = aws_api_gateway_resource.resource[each.key].id
  http_method        = each.value["http_method"]
  authorization      = each.value["authorization_type"]
  request_models     = try(each.value.request_models, {})
  request_parameters = each.value.request_parameters

}

resource "aws_api_gateway_integration" "integration" {
  for_each                = var.resources
  rest_api_id             = aws_api_gateway_rest_api.iddw.id
  resource_id             = aws_api_gateway_resource.resource[each.key].id #aws_api_gateway_resource.id
  http_method             = each.value.http_method
  integration_http_method = each.value.integration_http_method
  type                    = each.value.integration_type
  connection_type         = each.value.integration_conn_type
  #connection_id (Optional) ID of the VpcLink used for the integration. Required if connection_type is VPC_LINK
  uri = each.value.integration_uri
  #credentials
  request_templates  = try(each.value.integration_request_templates, {})
  request_parameters = each.value.integration_request_parameters

}

resource "aws_api_gateway_integration_response" "integration_response" {
  for_each            = var.resources
  rest_api_id         = aws_api_gateway_rest_api.iddw.id
  resource_id         = aws_api_gateway_resource.resource[each.key].id #aws_api_gateway_resource.id
  http_method         = each.value.integration_http_method
  status_code         = each.value.integration_response_status_code
  content_handling    = try(each.value.integration_response_content_handling, null) #unused resource
  response_parameters = try(each.value.integration_response_response_parameters, {})
  response_templates  = try(each.value.integration_response_templates, {})
  selection_pattern   = try(each.value.integration_response_selection_pattern, "")

}

resource "aws_api_gateway_method_response" "method_response" {
  for_each        = var.resources
  rest_api_id     = aws_api_gateway_rest_api.iddw.id
  resource_id     = aws_api_gateway_resource.resource[each.key].id #aws_api_gateway_resource.id
  http_method     = each.value.http_method
  status_code     = each.value.method_response_status_code
  response_models = each.value.response_models

}

Input variable:

variable "resources" {
  type = map(object({
    path_part                        = string,
    http_method                      = string,
    authorization_type               = string
    api_key_required                 = bool,
    request_parameters               = map(string)
    method_response_status_code      = string,
    response_models                  = map(string)
    integration_type                 = string,
    integration_http_method          = string,
    integration_uri                  = string,
    integration_conn_type            = string,
    integration_request_parameters   = map(string),
    integration_passthru             = string,
    integration_timeout              = string,
    integration_cache_namespace      = string
    integration_response             = map(string)
    integration_response_status_code = string,
  }))
}

This is the error it’s throwing ONLY when doing a full deploy from scratch:

╷
│ Error: creating API Gateway Integration: NotFoundException: Invalid Method identifier specified
│ 
│   with module.susig_gw.aws_api_gateway_integration.integration["axnadmin-token"],
│   on api-gateway/main.tf line 59, in resource "aws_api_gateway_integration" "integration":
│   59: resource "aws_api_gateway_integration" "integration" {
│ 
╵
╷
│ Error: creating API Gateway Integration: NotFoundException: Invalid Method identifier specified
│ 
│   with module.susig_gw.aws_api_gateway_integration.integration["otp"],
│   on api-gateway/main.tf line 59, in resource "aws_api_gateway_integration" "integration":
│   59: resource "aws_api_gateway_integration" "integration" {
│ 
╵
╷
│ Error: putting API Gateway Integration Response: NotFoundException: Invalid Method identifier specified
│ 
│   with module.susig_gw.aws_api_gateway_integration_response.integration_response["axnadmin-token"],
│   on api-gateway/main.tf line 75, in resource "aws_api_gateway_integration_response" "integration_response":
│   75: resource "aws_api_gateway_integration_response" "integration_response" {
│ 
╵
╷
│ Error: putting API Gateway Integration Response: NotFoundException: Invalid Method identifier specified
│ 
│   with module.susig_gw.aws_api_gateway_integration_response.integration_response["otp"],
│   on api-gateway/main.tf line 75, in resource "aws_api_gateway_integration_response" "integration_response":
│   75: resource "aws_api_gateway_integration_response" "integration_response" {
│ 
╵
╷
│ Error: creating API Gateway Method Response: NotFoundException: Invalid Method identifier specified
│ 
│   with module.susig_gw.aws_api_gateway_method_response.method_response["otp"],
│   on api-gateway/main.tf line 88, in resource "aws_api_gateway_method_response" "method_response":
│   88: resource "aws_api_gateway_method_response" "method_response" {

It’s the same issue folks are experiencing over at this git issue, but it hasn’t been addressed. I thought i might try my luck here.

Hi @susie-idw,

It’s been a long time since I used API Gateway so I don’t remember all of the details, but I do remember that the API Gateway API requires creating all of the objects related to a resource in a particular order, so I think the problem in your case is that you configuration doesn’t give Terraform information about the correct ordering and so Terraform could try to create these objects in potentially any order, which will fail if the order doesn’t match what the remote API requires.

When I had this problem I fixed it by changing the references between resources to better describe the required order. I don’t actually remember which order is required so I can’t show a full example but I will describe the general idea and then hopefully you can use your knowledge of API Gateway to complete it.

Currently your “integration” config refers only to the rest API and resource objects, so Terraform can’t see that the integration depends on the method. You can fix that by accessing the relevant settings through the method objects instead:

resource "aws_api_gateway_integration" "integration" {
  for_each                = var.resources
  rest_api_id             = aws_api_gateway_rest_api.iddw.id
  resource_id             = aws_api_gateway_resource.resource[each.key].id
  http_method             = aws_api_gateway_method.method.http_method
  integration_http_method = each.value.integration_http_method
  # ...
}

Notice that the http_method argument now refers to the corresponding argument of the method object, instead of referring to each.value. This tells Terraform that the method must be created first so that its http_method attribute will be finalized before trying to create the integration.

I think you will also need to make a similar change to the “integration response” object so that its http_method refers to the integration’s integration_http_method attribute, and then the method response must refer to the integration response. If you add all of these connections then Terraform will understand that it should create in the following order:

  • rest api
  • resource
  • method
  • integration
  • integration response
  • response

As I mentioned above I’m not sure that the above is actually the correct order, so you will need to refer to the API Gateway documentation to confirm, but whichever ordering is correct the general approach will be the same: make sure each resource block refers at least once to the resource that should be created before it.

Thanks @apparentlymart. In the end, it was a “dependency” issue. It’s a little wonky on the destroy, but per api gw ui, the order is: method, integration, integration response, method response.

Creating an API gateway using loops has been a difficult task. I saw there was a module, but not for REST. Is there one i’m missing?