以前、API GatewayのREST APIをTerraformから作成し、Serverless Frameworkからデプロイする方法の1つを紹介しました。
今回は、同じようにTerraformで作成したHTTP APIに対してデプロイします。
はじめに
以前にREST APIで行ったように、なるべくTerraform側に設定を寄せていきます。
ただし、APIのURLに関わる部分等はServerless Frameworkで設定します。
イメージとしては、
- ログ出力や監視等の設定はインフラ担当がTerraformで行う
- APIの実装とURLパスの設定は開発担当がServerless Frameworkで行う
という状況です。
REST APIとの違い
比較概要
API GatewayのHTTP APIはREST APIよりも安価ですが、機能も少なくなっています。
両者の違いはAWSの以下のページにまとめられています。
ここにないところで、AWSのサービス統合で対応しているサービスもHTTP APIの方が少ないようです。
何ができて何ができないのか把握した上で選択する必要があります。
以前のブログ記事でREST APIへデプロイしたときとの主な違いは以下のようになります。
以下の点について説明します。
- ステージ作成のためにデプロイメント不要(オートデプロイも可能)
- APIのパスはルートで設定(REST APIより簡易的)
$default
ステージを作れる- MOCK統合がない
ステージ作成のためにデプロイメント不要(オートデプロイも可能)
ステージを設定するためにデプロイメントが必須では無くなります。
アクセスログの設定はステージで行うため、ステージの作成が簡単になるのは嬉しいところです。
REST APIでは、ステージを作成するためにデプロイメントを指定する必要がありました。
さらに、デプロイメント作成のためには何かしらのAPIが存在する必要もあり、Terraformのコード量が増えてしまいます。
HTTP APIでは、URLを何も定義していない状態でデプロイせずにステージを作成できます。
REST APIのときよりも、Terraformのコード量は圧倒的に少なくなります。
さらに、HTTP APIではオートデプロイ機能も存在するため、デプロイメントを気にする必要はありません。
APIのパスはルートで設定(REST APIより簡易的)
/test/test1
というGET APIを作成するとき、REST APIでは以下のようにAPIのURLとメソッドを定義します。
- ルートリソースに紐づいた
test
リソースを定義する test
リソースに紐づいたtest1
リソースを定義するtest1
リソースに紐づいたGETメソッドを定義する
Terraformや手で作成するのは面倒な部分です。
それに対して、HTTP APIでは以下のようになります。
GET /test/test1
ルートを定義する
REST APIよりもシンプルで分かりやすい設定になります。
また、HTTP APIでは$default
という特別なルートを作成し、他のルートに当てはまらないリクエストを処理することも可能です。
$default
ステージを作れる
ステージにはdev
やprod
等の名前をつけますが、HTTP APIでは$default
という特別なステージを作成できます。
$default
ステージでは、API Gatewayデフォルトのエンドポイント(URL)にステージ名が入りません。
たとえばdev
ステージの場合、前述の/test/test1
APIに対してAPI Gatewayは以下のようなURLを生成します。
https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/dev/test/test1
これが$default
ステージの場合は以下のようになります。
https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/test/test1
ステージ名がURLに含まれません。
MOCK統合がない
REST APIでは、固定値の応答をAPI Gatewayだけで行えます。そのときに使うのがMOCK統合です。
HTTP APIではMOCK統合が存在しません。
APIのモックを作成するときもバックエンドが必要そうです。
作成するリソースの境界
ここから、実際にHTTP APIを作成していきたいと思います。
今回、API Gatewayに関しては以下のようなリソースを作成します。
デプロイメントがないため、REST APIのときと比べると凄くシンプルになっています。
Terraformで作成するのはaws_apigatewayv2_api
とaws_apigatewayv2_stage
だけです。
Serverless Frameworkで作成されるのはAWS::ApiGatewayV2::Integration
とAWS::ApiGatewayV2::Route
だけです。
TerraformでAPIを作成してデプロイしていたのに比べるとTerraformのコード量はかなり少なくなります。
気を付けるのは、Serverless Frameworkはデプロイメントを作成しないということです。
そのため、ステージにはオートデプロイを設定しておきます。
次から実際の設定を見ていきます。
Terraformの設定
まず始めに、HTTP APIとステージを作成するコードです。
# HTTP API resource "aws_apigatewayv2_api" "api" { name = "${var.env}-test-http-api" protocol_type = "HTTP" } resource "aws_apigatewayv2_stage" "default" { api_id = aws_apigatewayv2_api.api.id name = "$default" auto_deploy = true default_route_settings { throttling_burst_limit = 1 throttling_rate_limit = 1 } }
ステージにauto_deploy
を設定しているのがポイントです。
アクセスログの出力等はいれていませんので、必要に応じて設定をいれてください。
今回は、念のためスロットリングのみ設定しています。
リソースの作成はここまでですが、最後にServerless Frameworkに渡す必要のある値をoutput
します。
output "apigw_api_id" { value = aws_apigatewayv2_api.api.id }
Serverless Frameworkの設定に必要なので、次へ進む前にapply
して実際にHTTP APIを作成してください。
serverless.ymlの設定
Serverless Frameworkのserverless.ymlに、上で作成したHTTP APIを設定します。
特別に必要な設定は以下の箇所のみです。
provider: httpApi: id: "<<HTTP APIのID(Terraformでoutputとしたapigw_api_id)>>"
作成したAPIのIDを設定するだけです。
あとは、REST APIのログ設定等を入れないように気を付けながら通常通りserverless.ymlの設定をおこなってください。
たとえば、以下のようになります。
service: apigwhttptest frameworkVersion: '3' provider: name: aws runtime: python3.11 stage: ${opt:stage, self:custom.defaultStage} region: ap-northeast-1 httpApi: id: xxxxxxxxxx custom: defaultStage: dev package: individually: true excludeDevDependencies: true patterns: - '!**' functions: ${file(./conf/functions.yml)}
実際のLambda関数の定義はfunctions.ymlという別ファイルにしています。
内容は以下の通りです。
test1: handler: functions/test/test.handler role: arn:aws:iam::123456789012:role/${self:provider.stage}-api-lambda-test disableLogs: true package: patterns: - functions/test/** events: - httpApi: path: /test/test1 method: GET
events
でAPIのパスとメソッドを設定しているのがポイントです。
REST APIのときとの違いもevents
以下だけになります。
REST APIでは以下のようになっていました。
events: - http: path: /test/test1 method: GET
REST APIのときにhttp
だったものがhttpApi
になっているだけです。
Lambda統合のペイロード形式バージョン
HTTP APIをLambda統合で使うとき、ペイロードの形式のバージョンを選択できます。
これは、Lambda関数に渡されるイベントとLambda関数が出力するレスポンスの形式です。
1.0
がREST APIと同じ形式です。
この設定はServerless Frameworkのserverless.yml(またはそこから読み込まれるファイル)で行います。
provider
の下に設定することで、全体の共通設定を行うことができます。
設定にするには、先ほどAPI IDを設定したところにpayload
を記載します。
以下の例では、REST APIと同じ形式である1.0
を設定しています。
provider: httpApi: id: xxxxxxxxxx payload: '1.0'
API個別に設定する場合は、payload
をLambda関数の設定に記載します。
(上記provider
の設定をAPI個別に上書きできます)
test1: handler: functions/test/test.handler role: arn:aws:iam::123456789012:role/${self:provider.stage}-api-lambda-test disableLogs: true package: patterns: - functions/test/** httpApi: payload: '1.0' events: - httpApi: path: /test/test1 method: GET
package
とevents
の間に、payload
を含むhttpApi
の設定を追加しています。
なお、両方とも省略した場合は2.0
が選択されるようです。
(Serverless Frameworkのバージョン等により異なる場合があります)
最後に
今回は、Terraformで構築したHTTP APIにServerless Frameworkからデプロイする方法について紹介しました。
TerraformのコードはREST APIのときよりも少なく、簡単に構築が可能です。
さらにHTTP APIの方がREST APIより安価でもあるので、積極的に使っていきたい気持ちはあります。
しかし、REST APIよりも機能が限定的なため慎重に考える必要があります。
HTTP APIでは、リソースポリシーによる接続元IPアドレスの制限もAWS WAFによるセキュリティ対策も行えません。
これでは、利用できるシーンが限られてしまうのではないでしょうか。
AWS WAFだけでも対応してくれれば思います。