4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Terraformを使ってAPI GatewayとlambdaでAPIを構築する

Last updated at Posted at 2025-06-26

はじめに

今回は、Terraformを使ってAWSのAPI GatewayとLambdaを組み合わせたWeb API環境を構築してみます。

簡単な内容にはなりますが、実際に動かした手順とエラーが出たポイントについて説明できればと思います。

Terraformについて

Terraformとは、クラウドやオンプレミスのリソースを人間が読める構成ファイルで定義し、バージョン管理や再利用、共有ができるInfrastructure as Code(IaC)ツールです。

一貫性のあるワークフローを用いて、インフラのライフサイクル全体を通じてプロビジョニングや管理を行うことが可能です。

詳しくは公式ドキュメントをご覧ください。

実装について

Lambdaのコード作成

index.js
const awsServerlessExpress = require('aws-serverless-express');
const app = require('./app');
const server = awsServerlessExpress.createServer(app);

exports.handler = (event, context) => awsServerlessExpress.proxy(server, event, context);

app.js
const serverlessExpress = require('aws-serverless-express/middleware');
var express = require('express');
var app = express();

app.use(serverlessExpress.eventContext());

app.get('/', (req, res) => {
    res.send({message: "Hello World"});
});

module.exports = app

TerraFormコード作成

aws.tf
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

provider "aws" {
  region = "ap-northeast-1"
  default_tags {
    tags = {
      env = "cnsi"
    }
  }
}
lambda.tf
data "archive_file" "test_function_name" {
  type        = "zip"
  source_dir  = "lambda"
  output_path = "./test_function_name.zip"
}

resource "aws_lambda_function" "test_function_name" {
  filename         = data.archive_file.test_function_name.output_path
  function_name    = "test_function_name"
  role             = aws_iam_role.test_lambda_role.arn
  handler          = "index.handler"
  source_code_hash = data.archive_file.test_function_name.output_base64sha256
  runtime          = "nodejs22.x"

  memory_size = 128
  timeout     = 60
}

resource "aws_iam_role" "test_lambda_role" {
  name = "test_lambda_role"

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

resource "aws_lambda_permission" "apigw_lambda" {
  statement_id  = "AllowExecutionFromAPIGateway"
  action        = "lambda:InvokeFunction"
  function_name = aws_lambda_function.test_function_name.function_name
  principal     = "apigateway.amazonaws.com"
  source_arn = "${aws_api_gateway_rest_api.test_api.execution_arn}/*/*/*"
}
api.tf
resource "aws_api_gateway_rest_api" "test_api" {
  name = "test_api"
  endpoint_configuration {
    types = ["REGIONAL"]
  }
}

resource "aws_api_gateway_method" "test_api_method_root" {
  rest_api_id   = aws_api_gateway_rest_api.test_api.id
  resource_id   = aws_api_gateway_rest_api.test_api.root_resource_id
  http_method   = "ANY"
  authorization = "NONE"
}

resource "aws_api_gateway_resource" "test_api_resource" {
  path_part   = "{proxy+}"
  parent_id   = aws_api_gateway_rest_api.test_api.root_resource_id
  rest_api_id = aws_api_gateway_rest_api.test_api.id
}

resource "aws_api_gateway_method" "test_api_method" {
  rest_api_id   = aws_api_gateway_rest_api.test_api.id
  resource_id   = aws_api_gateway_resource.test_api_resource.id
  http_method   = "ANY"
  authorization = "NONE"
}

resource "aws_api_gateway_integration" "test_api_proxy" {
  rest_api_id             = aws_api_gateway_rest_api.test_api.id
  resource_id             = aws_api_gateway_resource.test_api_resource.id
  http_method             = aws_api_gateway_method.test_api_method.http_method
  integration_http_method = "POST"
  type                    = "AWS_PROXY"
  uri                     = aws_lambda_function.test_function_name.invoke_arn
}

resource "aws_api_gateway_integration" "test_api_proxy_root" {
  rest_api_id             = aws_api_gateway_rest_api.test_api.id
  resource_id             = aws_api_gateway_rest_api.test_api.root_resource_id
  http_method             = aws_api_gateway_method.test_api_method_root.http_method
  integration_http_method = "POST"
  type                    = "AWS_PROXY"
  uri                     = aws_lambda_function.test_function_name.invoke_arn
}

resource "aws_api_gateway_deployment" "test_deployment" {
  depends_on = [aws_api_gateway_integration.test_api_proxy]

  rest_api_id = aws_api_gateway_rest_api.test_api.id
}

resource "aws_api_gateway_stage" "test_stage" {
  stage_name    = "dev"
  rest_api_id   = aws_api_gateway_rest_api.test_api.id
  deployment_id = aws_api_gateway_deployment.test_deployment.id
}

Terraformで実行したコマンド

実際に使ったコマンドは以下になります。
1.プロジェクトの初期化

$ terraform init

2.リソースの作成・変更・削除を行わずに、実行予定の操作を表示

$ terraform plan

3.インフラの作成・変更・削除を実行

$ terraform apply

実際に動かしてみた結果

AWSマネジメントコンソールからLambdaとAPI Gatewayを確認したところ、実際に環境が構築されていることを確認できました。

Lambda
lambda.png
API Gateway
aoigateway.png

上記の確認ができたので、APIのURLを確認し、ブラウザでアクセスしてみました。

レスポンスの確認
get.png

このように、レスポンスが取得できることを確認しました。

確認ができたら、環境を削除するために以下のコマンドを実行します。
(定義されているリソースをすべて削除)

$ terraform destroy

Terraformのコマンド実行時にエラー

AWSプロバイダーのバージョン違いによるエラー

terraform plan を実行した際に以下のエラーが発生しました。

エラー内容

Error: expected runtime to be one of [nodejs nodejs4.3 nodejs6.10 nodejs8.10 nodejs10.x nodejs12.x nodejs14.x nodejs16.x java8 java8.al2 java11 python2.7 python3.6 python3.7 python3.8 python3.9 dotnetcore1.0 dotnetcore2.0 dotnetcore2.1 dotnetcore3.1 dotnet6 nodejs4.3-edge go1.x ruby2.5 ruby2.7 provided provided.al2 nodejs18.x], got nodejs22.x
│
│   with aws_lambda_function.test_function_name,
│   on lambda.tf line 13, in resource "aws_lambda_function" "test_function_name":
│   13:   runtime          = "nodejs22.x"

エラーメッセージによると、Lambdaのランタイムに指定可能な値は固定のリストの中から選ぶ必要があり、nodejs22.x は使用できないことがわかりました。

設定していたAWSプロバイダーのバージョンが古いため、nodejs22.x をサポートしておらず、認識されずエラーとなっていました。

aws.tf のプロバイダー指定を ~> 3.0 から、nodejs22.x をサポートする最新のバージョン(例:~> 5.0)に上げます。

aws.tf
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0" //はじめ3.0を指定していた
    }
  }
}

バージョンを変更した後、以下のコマンドでプロバイダーのアップグレードを反映します。

$ terraform init -upgrade

これにより最新バージョンが適用され、再度 terraform plan を実行するとエラーがなくなりました。

おわりに

今回はTerraformを使ってAPI GatewayとLambdaを組み合わせたWeb API環境を構築しました。

Terraform自体を初めて触ることもあり、いくつか苦戦する部分もありました。特にバージョン差異による動作の違いは注意が必要だと感じました。

今回は簡単な構成でしたが、今後はEC2やALBなど、他のAWSリソースでも構築を行い、さらに理解を深めていきたいと思います。

4
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?