0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

API Gateway REST APIとHTTP APIの違い — 機能・料金・レイテンシをなぜそうなるかから選ぶ

0
Posted at

本記事の目的

API Gateway で新規 API を作るとき、最初に「REST API / HTTP API / WebSocket API」のどれにするかを迫られます。本記事は REST API と HTTP API の機能・料金・レイテンシ差が「なぜ生まれるか」を内部処理量の観点で説明し、後から作り直さなくて済む選び方を示します。

結論(先に答え)

  • REST 固有機能(AWS WAF / API キー・使用量プラン / リクエスト検証・本文変換 / キャッシュ / Private エンドポイント / X-Ray・実行ログ)が要るなら REST API、要らなければ HTTP API。
  • 料金差・レイテンシ差は値引きや性能差ではなく、1リクエストあたりに走る内部処理量の差から生じる同根の現象です。
  • 後からの REST ⇄ HTTP 切り替えは API の作り直しに近く高コストです。要件は最初に確定させましょう。

API Gateway の3つの API タイプ

  • REST API — API 管理(API キー・使用量プラン)、キャッシュ、リクエスト/レスポンス変換、WAF 連携、Private エンドポイントを備える従来プロダクト。
  • HTTP API — 機能を最小限に絞り低価格・低レイテンシで提供する後発プロダクト。JWT オーソライザーなど一部は HTTP API のみ。
  • WebSocket API — 双方向通信向けで用途が異なるため本記事は位置づけのみ。

以降は WebSocket を除いた REST API と HTTP API の比較に集中します。

なぜ差が出るのか — 内部パイプラインの長さ

機能・料金・レイテンシの差は、すべて API Gateway がリクエスト1本を処理する際のステップ数に帰着します。

REST API:多段パイプライン

リクエストは次の段を順に通ります。

  • 各段に VTL(マッピングテンプレート)評価・検証フックが挟まります。
  • この多段構造こそが、本文変換・リクエスト検証・カスタムゲートウェイレスポンスといった豊富な機能を可能にします。
  • 一方で、リクエストごとに評価される制御処理が増え、その分のオーバーヘッドが生まれます。
  • デプロイは「ユーザー制御デプロイ」。ステージへ明示デプロイして初めて反映(カナリアも可能)。
  • エンドポイントは Edge-optimized / Regional / Private の3種。

HTTP API:ルート→統合の短経路

  • 「ルート(route)」に「統合(integration)」を直接ひもづけるシンプルなモデルです。多段の変換パイプラインを持たず、プロキシ統合が中心です。
  • パイプラインが短い → これが低レイテンシ・低価格の根拠です。
  • 自動デプロイ対応(変更が即反映)。$default ルート / $default ステージで概念も簡略化。
  • エンドポイントは Regional のみ(Edge-optimized・Private 非対応)。

「機能が少ない=処理が少ない=オーバーヘッドが小さい」。この1本の因果が、後述の料金差・レイテンシ差・機能差すべての元になっています。

機能比較(REST API vs HTTP API)

大半の機能は両対応です。選定に効くのは「差がある機能」だけなので、まずそれを抜き出します(✅=対応 / ❌=非対応)。

カテゴリ 機能 REST HTTP
エンドポイント Edge-optimized
エンドポイント Private
セキュリティ バックエンド認証用クライアント証明書
セキュリティ AWS WAF 連携
認可 リソースポリシー
認可 JWT オーソライザー
API 管理 API キー / 使用量プラン / クライアント単位レート制限
開発 キャッシュ
開発 リクエスト検証 / 本文変換
開発 自動デプロイ
統合 AWS Cloud Map へのプライベート統合
監視 X-Ray / 実行ログ / Firehose 出力
  • HTTP API にできなくて困りやすい代表格: AWS WAF・API キー/使用量プラン・キャッシュ・リクエスト検証・X-Ray・実行ログ。
  • 逆に HTTP API 側の強み: JWT オーソライザー・自動デプロイ・Cloud Map 統合。
全機能対応表(両対応の機能を含む全リスト・クリックで展開)
カテゴリ 機能 REST API HTTP API
エンドポイント Edge-optimized
エンドポイント Regional
エンドポイント Private
セキュリティ Mutual TLS
セキュリティ バックエンド認証用クライアント証明書
セキュリティ AWS WAF 連携
認可 IAM
認可 リソースポリシー
認可 Amazon Cognito ✅(JWT 経由)
認可 Lambda オーソライザー
認可 JWT オーソライザー
API 管理 カスタムドメイン
API 管理 API キー
API 管理 クライアント単位レート制限
API 管理 使用量プラン
API 管理 デベロッパーポータル
開発 CORS 設定
開発 キャッシュ
開発 テスト呼び出し(コンソール)
開発 自動デプロイ
開発 カナリアリリース
開発 リクエスト検証
開発 リクエストパラメータ変換
開発 リクエスト本文変換
開発 カスタムゲートウェイレスポンス
統合 Public HTTP 統合
統合 AWS サービス統合
統合 Lambda 統合
統合 NLB へのプライベート統合
統合 ALB へのプライベート統合
統合 AWS Cloud Map へのプライベート統合
統合 モック統合
統合 レスポンスストリーミング
監視 CloudWatch メトリクス
監視 アクセスログ → CloudWatch Logs
監視 アクセスログ → Data Firehose
監視 実行ログ
監視 AWS X-Ray トレース

出典:
 【AWS公式】
 ・REST API と HTTP API のどちらかを選択する

認証・認可方式の違い

方式 REST API HTTP API
IAM 認可
Lambda オーソライザー
Mutual TLS
リソースポリシー
バックエンド認証用クライアント証明書
Cognito ユーザープールオーソライザー(専用型) ❌ ※1
JWT オーソライザー ❌ ※2

補足:

  • ※1 REST API は「Cognito ユーザープールオーソライザー」として直接連携します。HTTP API は JWT オーソライザー経由で連携します(Cognito 専用型ではなく JWT として扱います)。
  • ※2 REST API で OIDC/OAuth の JWT を検証したい場合は JWT オーソライザーがないため、Lambda オーソライザーで自前検証します。

選択軸

要望 タイプ
Cognito ユーザープールを直接つなぎたい REST
OIDC/OAuth の JWT を標準機能で検証したい HTTP

料金の違い — なぜ HTTP API は安いのか

課金体系はどちらもリクエスト数課金です。HTTP API は機能を絞ることで REST API より大幅に低価格に設定されています。

なぜ単価が違うのか

前述のパイプライン長の差が、そのまま料金差として現れます。REST API の単価には、リクエストごとに走る次の制御処理コストが織り込まれています。

  • API キー検証・使用量プランの照合
  • WAF 連携(WebACL 評価)
  • VTL マッピングテンプレート評価
  • リクエスト検証

HTTP API はこれらの処理自体を持たないため、1 リクエストあたりのゲートウェイ側リソース消費が小さくなります。

見落としやすいコスト

コスト項目 REST API HTTP API
リクエスト単価
キャッシュ(メモリサイズ別・時間課金) 有効化すると発生 機能なし・発生しない
AWS WAF WebACL 評価 WAF を使う場合に別途発生 非対応

コスト試算は「リクエスト単価の差」だけでなく、キャッシュ課金の有無・WAF 側課金まで含めて比較してください。

単価・段階課金の閾値はリージョン・改定で変動します。必ず API Gateway 料金ページ で最新値を確認してください。

レイテンシ・パフォーマンスの違い

Latency メトリクスの内訳で見ると、バックエンド処理時間(IntegrationLatency)は変わらず、ゲートウェイ自身のオーバーヘッド部分が HTTP API で小さくなります。

Latency(全体)
 ├─ IntegrationLatency … バックエンド処理時間(Lambda 等)※ どちらも同じ
 └─ ゲートウェイ自身のオーバーヘッド … ★ HTTP API ではここが小さい
REST API HTTP API
処理経路 メソッドリクエスト → VTL評価 → 統合 → VTL評価 → メソッドレスポンス ルート → 統合(変換ステップなし)
ゲートウェイオーバーヘッド 大(各段で評価処理が走る)

どちらを選ぶべきか(比較表)

機能・要件 REST API HTTP API WebSocket API
双方向通信(Push/Subscribe)
AWS WAF 直接適用
APIキー・使用量プラン
リクエスト検証・本文変換(VTL)
Privateエンドポイント(VPC内)
Edgeエンドポイント(CloudFront経由)
キャッシュ・X-Ray・実行ログ
JWTオーソライザー(OIDC/OAuth)
Cloud Map統合・自動デプロイ
相対コスト

REST 固有機能が1つも不要なら HTTP API が第一候補です。

エッジ配信が必要な場合

HTTP API は Regional エンドポイントのみです。Edge-optimized(CloudFront 経由の低レイテンシ配信)が要件なら次のいずれかを選んでください。

  • REST API — Edge-optimized エンドポイントをそのまま使う
  • HTTP API + 自前 CloudFront — HTTP API を Regional で建て、前段に CloudFront を置く

典型シナリオでの当てはめ

シナリオ 選択 理由
社内マイクロサービス間 API(ALB/NLB 背後・IAM/Lambda オーソライザー認可) HTTP API REST 固有機能が不要なことが多く、低レイテンシ・低コストの恩恵が大きい
外部パートナー公開 API(クライアント単位で課金・流量制限) REST API API キー・使用量プランが必須
B2C モバイル/SPA バックエンド(Cognito/OIDC の JWT 検証) HTTP API JWT オーソライザーを標準で使える(WAF 要件なら前段 CloudFront+WAF か REST)
VPC 内クローズドな API(VPC エンドポイント経由のみ) REST API Private エンドポイントが REST のみ
公開 API でボット対策・地理ブロック等 WAF 必須 REST API WAF 直接連携が REST のみ(または HTTP API + CloudFront に WAF)

メトリクス(CloudWatch)— 移行時の落とし穴

REST API と HTTP API は メトリクス名・ディメンションが異なるため、ダッシュボード/アラームを使い回せません。

REST API HTTP API
名前空間 AWS/ApiGateway AWS/ApiGateway
クライアントエラー 4XXError 4xx
サーバーエラー 5XXError 5xx
リクエスト数 Count Count
全体レイテンシ Latency Latency
バックエンド処理時間 IntegrationLatency IntegrationLatency
キャッシュ CacheHitCount / CacheMissCount (なし)
データ処理量 (なし) DataProcessed
主ディメンション ApiName(+ Stage, Method, Resource ApiId(+ Stage, Method, Resource
  • 最大の罠: エラーメトリクス名が 4XXError(REST)と 4xx(HTTP)で綴りが違い、ディメンションも ApiName vs ApiId で異なります。REST → HTTP 移行時にアラームが無反応のまま放置されやすいです。
  • メソッド/ルート単位メトリクス(Method, Resource, Stage)は両タイプとも詳細メトリクスを明示有効化しないと送信されません(追加課金あり)。
  • HTTP API には DataProcessed(処理バイト数)がありますが、REST API にはありません。逆にキャッシュ系メトリクスは REST API のみです。

運用・切り分けの基本

  • LatencyIntegrationLatency並べて見て差分(=ゲートウェイオーバーヘッド)を把握します。REST → HTTP 移行のレイテンシ改善効果はここで定量化できます。
  • レイテンシ悪化の切り分け: IntegrationLatency が大きければバックエンド側(Lambda コールドスタート等)、差分が大きければゲートウェイ側(REST の VTL 評価・検証など)を疑います。
  • REST API でキャッシュを有効化した場合は CacheHitCount / CacheMissCount のヒット率を監視します。ヒット率が低ければキャッシュ課金に見合わず、TTL 見直しや HTTP API への移行を検討する材料になります。

出典:
 【AWS公式】
 ・Amazon API Gateway のディメンションとメトリクス
 ・API Gateway で HTTP API の CloudWatch メトリクスをモニタリングする

よくある誤解

  1. 「HTTP API は REST じゃない」
    • → 誤りです。HTTP API も RESTful なインタフェースです。名前が紛らわしいだけで、実体は「REST API の廉価版」です。
  2. 「安いから常に HTTP API でいい」
    • → WAF・API キー・キャッシュ・リクエスト検証・Private エンドポイントが必要になった瞬間に詰みます。REST への切り替えには API の作り直しが必要で高コストです。
  3. 「Cognito を使うなら REST API だけ」
    • → HTTP API でも JWT オーソライザー経由で Cognito を使えます。連携の形が違うだけです。
  4. 「メトリクス/アラームはそのまま流用できる」
    • 4XXError vs 4xxApiName vs ApiId で異なるため流用できません。
  5. 「HTTP API に WAF を直接付けられる」
    • → 不可です。WAF が必要なら REST API を選ぶか、HTTP API の前段に CloudFront を置いて CloudFront に WAF を適用します。

簡易的な検証リソース構成

REST API と HTTP API を API ごとに独立した Lambda バックエンドで並べて立て、レイテンシ・コストを実測比較するための Terraform サンプルです。

構成図

検証リソース構成図

検証時の前提

同一コードをデプロイした Lambda を API ごとに用意することで、バックエンドの差異を排除しゲートウェイアーキテクチャの速度差を比較します。
ただし HTTP API は変換パイプライン非搭載のため Lambda 呼び出しオーバーヘッドが CloudWatch の最小分解能(1ms)を下回り IntegrationLatency が発行されない場合があります。
その場合、GW overhead = Latency − IntegrationLatency での定量分離は HTTP 側では成立しないため、Latency の直接比較を用います。

Terraform

サンプルコード一式は GitHub で公開しています:
aws-apigw-rest-vs-http-sandbox

providers.tf — プロバイダ設定
terraform {
  required_version = ">= 1.10"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 6.0"
    }
    archive = {
      source  = "hashicorp/archive"
      version = "~> 2.0"
    }
  }
}

provider "aws" {
  region = var.aws_region
}
variables.tf — 変数定義
variable "aws_region" {
  description = "AWS region to deploy resources"
  type        = string
}

variable "project_name" {
  description = "Project name prefix used for resource naming and tags"
  type        = string
}
iam.tf — Lambda 用 IAM ロール
resource "aws_iam_role" "lambda" {
  name = "${var.project_name}-lambda"
  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Action    = "sts:AssumeRole"
      Effect    = "Allow"
      Principal = { Service = "lambda.amazonaws.com" }
    }]
  })

  tags = {
    Name    = "${var.project_name}-lambda"
    Project = var.project_name
  }
}

resource "aws_iam_role_policy_attachment" "lambda_basic" {
  role       = aws_iam_role.lambda.name
  policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
}
lambda.tf — バックエンド Lambda 関数(REST / HTTP 用に各1つ)
data "archive_file" "lambda_zip" {
  type        = "zip"
  source_file = "${path.module}/src/lambda_function.py"
  output_path = "${path.module}/src/lambda_function.zip"
}

resource "aws_lambda_function" "rest_backend" {
  function_name    = "${var.project_name}-rest-backend"
  runtime          = "python3.13"
  handler          = "lambda_function.lambda_handler"
  role             = aws_iam_role.lambda.arn
  filename         = data.archive_file.lambda_zip.output_path
  source_code_hash = data.archive_file.lambda_zip.output_base64sha256

  tags = {
    Name    = "${var.project_name}-rest-backend"
    Project = var.project_name
  }
}

resource "aws_lambda_function" "http_backend" {
  function_name    = "${var.project_name}-http-backend"
  runtime          = "python3.13"
  handler          = "lambda_function.lambda_handler"
  role             = aws_iam_role.lambda.arn
  filename         = data.archive_file.lambda_zip.output_path
  source_code_hash = data.archive_file.lambda_zip.output_base64sha256

  tags = {
    Name    = "${var.project_name}-http-backend"
    Project = var.project_name
  }
}

ハンドラ(src/lambda_function.py)はイベントのペイロードバージョン(1.0=REST API / 2.0=HTTP API)を判別し、API タイプや requestId 等のメタ情報をレスポンスに含めます。

api_rest.tf — REST API(多段パイプライン・明示デプロイ)
resource "aws_api_gateway_rest_api" "rest" {
  name = "${var.project_name}-rest"

  tags = {
    Name    = "${var.project_name}-rest"
    Project = var.project_name
  }
}

resource "aws_api_gateway_resource" "rest_proxy" {
  rest_api_id = aws_api_gateway_rest_api.rest.id
  parent_id   = aws_api_gateway_rest_api.rest.root_resource_id
  path_part   = "{proxy+}"
}

resource "aws_api_gateway_method" "rest_any" {
  rest_api_id   = aws_api_gateway_rest_api.rest.id
  resource_id   = aws_api_gateway_resource.rest_proxy.id
  http_method   = "ANY"
  authorization = "NONE" # PoC only — 本番では IAM or Lambda authorizer に変更
}

resource "aws_api_gateway_integration" "rest_lambda" {
  rest_api_id             = aws_api_gateway_rest_api.rest.id
  resource_id             = aws_api_gateway_resource.rest_proxy.id
  http_method             = aws_api_gateway_method.rest_any.http_method
  type                    = "AWS_PROXY"
  integration_http_method = "POST"
  uri                     = aws_lambda_function.rest_backend.invoke_arn
}

resource "aws_api_gateway_deployment" "rest" {
  rest_api_id = aws_api_gateway_rest_api.rest.id
  depends_on  = [aws_api_gateway_integration.rest_lambda]
}

resource "aws_api_gateway_stage" "rest" {
  rest_api_id   = aws_api_gateway_rest_api.rest.id
  deployment_id = aws_api_gateway_deployment.rest.id
  stage_name    = "dev"

  tags = {
    Name    = "${var.project_name}-rest-dev"
    Project = var.project_name
  }
}

resource "aws_lambda_permission" "rest" {
  statement_id  = "AllowRestAPI"
  action        = "lambda:InvokeFunction"
  function_name = aws_lambda_function.rest_backend.function_name
  principal     = "apigateway.amazonaws.com"
  source_arn    = "${aws_api_gateway_rest_api.rest.execution_arn}/*/*"
}
api_http.tf — HTTP API(ルート直結・auto_deploy)
resource "aws_apigatewayv2_api" "http" {
  name          = "${var.project_name}-http"
  protocol_type = "HTTP"

  tags = {
    Name    = "${var.project_name}-http"
    Project = var.project_name
  }
}

resource "aws_apigatewayv2_integration" "http_lambda" {
  api_id                 = aws_apigatewayv2_api.http.id
  integration_type       = "AWS_PROXY"
  integration_uri        = aws_lambda_function.http_backend.invoke_arn
  payload_format_version = "2.0"
}

resource "aws_apigatewayv2_route" "http_default" {
  api_id             = aws_apigatewayv2_api.http.id
  route_key          = "$default"
  target             = "integrations/${aws_apigatewayv2_integration.http_lambda.id}"
  authorization_type = "NONE" # PoC only — 本番では JWT or Lambda authorizer に変更
}

resource "aws_apigatewayv2_stage" "http" {
  api_id      = aws_apigatewayv2_api.http.id
  name        = "$default"
  auto_deploy = true

  default_route_settings {
    detailed_metrics_enabled = true
  }

  tags = {
    Name    = "${var.project_name}-http-default"
    Project = var.project_name
  }
}

resource "aws_lambda_permission" "http" {
  statement_id  = "AllowHttpAPI"
  action        = "lambda:InvokeFunction"
  function_name = aws_lambda_function.http_backend.function_name
  principal     = "apigateway.amazonaws.com"
  source_arn    = "${aws_apigatewayv2_api.http.execution_arn}/*/*"
}
outputs.tf — エンドポイント URL 出力
output "rest_api_url" {
  description = "REST API endpoint URL for latency measurement"
  value       = "${aws_api_gateway_stage.rest.invoke_url}/test"
}

output "http_api_url" {
  description = "HTTP API endpoint URL for latency measurement"
  value       = "${trimsuffix(aws_apigatewayv2_stage.http.invoke_url, "/")}/test"
}

確認手順

cd terraform
terraform init && terraform apply

# レイテンシを並べて計測(10回平均)
REST_URL=$(terraform output -raw rest_api_url)
HTTP_URL=$(terraform output -raw http_api_url)

for i in $(seq 10); do curl -o /dev/null -s -w "%{time_total}\n" "$REST_URL"; done
for i in $(seq 10); do curl -o /dev/null -s -w "%{time_total}\n" "$HTTP_URL"; done

CloudWatch の Latency を REST / HTTP で直接比較することで、ゲートウェイ自身の速度差を確認できます。
HTTP API は変換パイプラインを持たないアーキテクチャのため、ウォーム時の Lambda 呼び出しオーバーヘッドが CloudWatch の最小分解能 1ms を下回りIntegrationLatency が発行されない場合があります。
このため Latency − IntegrationLatency ではなく Latency の直接比較を使います。
使い終わったら terraform destroy でリソースを削除してください。

実測例:コールドスタート vs ウォームリクエスト

各エンドポイントに 10 回リクエストを送信した結果(単位: ms)。

1回目(コールドスタート) 2〜10回目 平均 2〜10回目 最小 2〜10回目 最大
REST API 115.8 ms 79.5 ms 68.4 ms 88.5 ms
HTTP API 75.2 ms 44.7 ms 38.4 ms 53.0 ms

CloudWatch メトリクスで見た内訳(ウォーム計測時):

両 API はそれぞれ独立した Lambda 関数に同一コードをデプロイしています。
REST API の IntegrationLatency は 27.3 ms を計測できましたが、HTTP API は変換パイプラインを持たないアーキテクチャのため、Lambda 呼び出しオーバーヘッドが CloudWatch の最小分解能(1ms)を下回りメトリクスとして発行されない場合があります。
その場合、GW overhead = Latency − IntegrationLatency による定量比較は HTTP API 側で成立しないため、ゲートウェイ速度差の比較には Latency を直接用います。

API タイプ Latency IntegrationLatency
REST API 30.86 ms 27.3 ms
HTTP API 3.8 ms < 1 ms(変換パイプライン非搭載のため CloudWatch 分解能未満・今回の検証では未発行)

考察:

  • コールドスタート時(curl 1 回目) は REST API が約 1.5 倍遅い(115.8 ms vs 75.2 ms)。Lambda を API ごとに分離し独立した初期状態で計測した結果、HTTP API のコールドスタートが速いという期待通りの傾向が得られた。
  • ウォームリクエスト時(curl 2〜10 回目) は REST API が約 1.8 倍遅い(79.5 ms vs 44.7 ms)。HTTP API の軽量なアーキテクチャによるゲートウェイオーバーヘッドの差が curl レベルでも一貫して観測できる。
  • CloudWatch Latency は REST API が約 8.1 倍大きい(30.86 ms vs 3.8 ms)。
    • HTTP API は変換パイプラインを持たないため Lambda 呼び出しオーバーヘッドが 1ms 未満となり IntegrationLatency は CloudWatch に発行されない場合がある。
      同一コードの Lambda を使っているため、Latency の直接比較がゲートウェイアーキテクチャの速度差を示す証拠として機能する。

まとめ

  • 機能・料金・レイテンシの差はすべて「内部パイプラインの長さ」の結果です。
  • REST 固有機能(WAF / API キー / リクエスト検証 / キャッシュ / Private エンドポイント / X-Ray)が1つでも要るなら REST API、それ以外は HTTP API が第一候補です。
  • 移行時の監視設計に注意。4XXError vs 4xxApiName vs ApiId の違いで既存アラームは流用できません。
  • 移行効果の定量化には REST 側の Latency − IntegrationLatency を事前に記録しておくと有用です(HTTP 側は IntegrationLatency が 1ms 未満で未発行の場合があるため Latency を直接比較)。
0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?