Skip to content

Instantly share code, notes, and snippets.

@Ninir
Created August 4, 2016 16:37
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save Ninir/6fa958e3308cbce73e2c7398523f428e to your computer and use it in GitHub Desktop.
Save Ninir/6fa958e3308cbce73e2c7398523f428e to your computer and use it in GitHub Desktop.
Create an AWS API Gateway with a POST method on the root resource targetting a given Lambda

Description

This helps creating an AWS API GW with a POST method on the root resource (i.e /) targetting a given Lambda.

The current Terraform documentation is exposing a Mock integration. Thus, a few options are missing when wanting to expose a Lambda integration instead.

There are a few things to know:

1. Add the integration HTTP Method

First of all, you will need to add the integration_http_method alongside the http_method, as in:

resource "aws_api_gateway_integration" "dummy_integration" {
  rest_api_id = "${aws_api_gateway_rest_api.dummy.id}"
  resource_id = "${aws_api_gateway_rest_api.dummy.root_resource_id}"
  http_method = "${aws_api_gateway_method.dummy_method.http_method}"
  integration_http_method = "${aws_api_gateway_method.dummy_method.http_method}"
  type = "AWS"
  uri = "arn:aws:apigateway:eu-west-1:lambda:path/2015-03-31/functions/${aws_lambda_function.dummy_lambda.arn}/invocations"
}

Not setting it would lead to this error:

[...] Error creating API Gateway Integration: BadRequestException: Enumeration value for HttpMethod must be non-empty

Even if it is explicitely written in the documentation, it is not really highlighted so this may be forgotten ;-)

2. Integration Response dependency

Then you will need to explicitely set the depends_on on the integration response as per this thread.

resource "aws_api_gateway_integration_response" "dummy_integration_response" {
  rest_api_id = "${aws_api_gateway_rest_api.dummy.id}"
  resource_id = "${aws_api_gateway_rest_api.dummy.root_resource_id}"
  http_method = "${aws_api_gateway_method.dummy_method.http_method}"
  status_code = "${aws_api_gateway_method_response.200.status_code}"
  depends_on  = ["aws_api_gateway_integration.dummy_integration"]
}

Not setting it would lead to this error:

[...] Error creating API Gateway Integration Response: NotFoundException: No integration defined for method

A future Terraform release might remove the need for this.

3. Target the API Gateway root resource

Finally, if you want to add a method on the root resource (i.e the first slash in the URL, /), the first idea that might come out would be to create a aws_api_gateway_resource resource and use it afterthat, as in:

resource "aws_api_gateway_resource" "dummy" {
  rest_api_id = "${aws_api_gateway_rest_api.dummy.id}"
  parent_id = "${aws_api_gateway_rest_api.dummy.root_resource_id}"
  path_part = ""
}

...

resource "aws_api_gateway_integration_response" "dummy_integration_response" {
  rest_api_id = "${aws_api_gateway_rest_api.dummy.id}"
  resource_id = "${aws_api_gateway_resource.dummy.id}"
  http_method = "${aws_api_gateway_method.dummy.http_method}"
  status_code = "${aws_api_gateway_method_response.200.status_code}"
}

...

However, as the path_part can not be empty nor be set to /, this is not the way to go (spoiler: it would throw an error for each case).

In order to target the root resource (i.e /), you will need to use the root_resource_id of your API Gateway, as in aws_api_gateway_rest_api.dummy.root_resource_id. The above code would then be (the third line changed):

resource "aws_api_gateway_integration_response" "dummy_integration_response" {
  rest_api_id = "${aws_api_gateway_rest_api.dummy.id}"
  resource_id = "${aws_api_gateway_rest_api.dummy.root_resource_id}"
  http_method = "${aws_api_gateway_method.dummy.http_method}"
  status_code = "${aws_api_gateway_method_response.200.status_code}"
}

Example usage

resource "aws_api_gateway_rest_api" "dummy" {
  name = "dummy-apigw"
  description = "Dummy API GW"
}

resource "aws_api_gateway_method" "dummy_method" {
  rest_api_id = "${aws_api_gateway_rest_api.dummy.id}"
  resource_id = "${aws_api_gateway_rest_api.dummy.root_resource_id}"
  http_method = "POST"
  authorization = "NONE"
}

resource "aws_api_gateway_integration" "dummy_integration" {
  rest_api_id = "${aws_api_gateway_rest_api.dummy.id}"
  resource_id = "${aws_api_gateway_rest_api.dummy.root_resource_id}"
  http_method = "${aws_api_gateway_method.dummy_method.http_method}"
  integration_http_method = "${aws_api_gateway_method.dummy_method.http_method}"
  type = "AWS"
  uri = "arn:aws:apigateway:eu-west-1:lambda:path/2015-03-31/functions/${aws_lambda_function.dummy_lambda.arn}/invocations"
}

resource "aws_api_gateway_method_response" "200" {
  rest_api_id = "${aws_api_gateway_rest_api.dummy.id}"
  resource_id = "${aws_api_gateway_rest_api.dummy.root_resource_id}"
  http_method = "${aws_api_gateway_method.dummy_method.http_method}"
  status_code = "200"
}

resource "aws_api_gateway_integration_response" "dummy_integration_response" {
  rest_api_id = "${aws_api_gateway_rest_api.dummy.id}"
  resource_id = "${aws_api_gateway_rest_api.dummy.root_resource_id}"
  http_method = "${aws_api_gateway_method.dummy_method.http_method}"
  status_code = "${aws_api_gateway_method_response.200.status_code}"
  depends_on = ["aws_api_gateway_integration.dummy_integration"]
}

resource "aws_iam_role" "iam_for_lambda" {
    name = "iam_for_lambda"
    assume_role_policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "sts:AssumeRole",
      "Principal": {
        "Service": "lambda.amazonaws.com"
      },
      "Effect": "Allow",
      "Sid": ""
    }
  ]
}
EOF
}

resource "aws_lambda_function" "dummy_lambda" {
  filename         = "mydummyfile.zip"
  function_name    = "dummy_lambda"
  role             = "${aws_iam_role.iam_for_lambda.arn}"
  handler          = "entrypoint.handler"
  runtime          = "python2.7"
  source_code_hash = "${base64sha256(file('mydummyfile.zip'))}"
}
@aok-solutions
Copy link

This was a great help! 👍

@niroliyanage
Copy link

Thank you !!!!

@wdtj
Copy link

wdtj commented Nov 25, 2019

I'm a bit confused. aws_api_gateway_rest_api has no root_resource_id attribute. And indeed I get the error:
aws_api_gateway_method.librarian_method: Error creating API Gateway Method: NotFoundException: Invalid Resource identifier specified
on

resource "aws_api_gateway_rest_api" "librarian_api" {...}

resource "aws_api_gateway_method" "librarian_method" {
resource_id = "aws_api_gateway_rest_api.librarian_api.root_resource_id"

@mousavii
Copy link

mousavii commented Feb 7, 2020

Thanks. it was great.

@fireman777
Copy link

I'm a bit confused. aws_api_gateway_rest_api has no root_resource_id attribute. And indeed I get the error:
aws_api_gateway_method.librarian_method: Error creating API Gateway Method: NotFoundException: Invalid Resource identifier specified
on

resource "aws_api_gateway_rest_api" "librarian_api" {...}

resource "aws_api_gateway_method" "librarian_method" {
resource_id = "aws_api_gateway_rest_api.librarian_api.root_resource_id"
Hi, here is a working example:
https://stackoverflow.com/questions/61072514/terraform-how-to-create-a-api-gateway-post-method-at-root

@lfreeitas
Copy link

thanks a lot

@szanata
Copy link

szanata commented Aug 26, 2020

Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment