こしあん
2024-12-28

API Gatewayのモック統合でHTMLページを表示


4{icon} {views}


API GatewayだけでHTMLページをホストする方法を、Terraformのモック統合で実践する手順を紹介しています。 文字化けを防ぐために、Content-TypeヘッダーやHTML内のcharset指定を正しく設定するポイントも解説しています。

はじめに

  • API Gatewayのモック統合を以前試したのだが、これの延長線上でAPI GatewayからHTMLページをホストできることを知ったので試してみた
  • DVAを勉強しているときに出てきて面白いなと思ったものなのだが、以前のコードを少し改造したらできた
  • Lambdaは不要で、API Gatewayだけでできる

できたもの

API GatewayだけでHTMLページをホストできている。不思議

文字コードの注意点

普通にやるとHTMLが文字化けしてしまうので、以下の点に注意する。

  1. Content-Type ヘッダーの不足または誤設定:
    • ブラウザが受信したコンテンツの文字エンコーディングを正しく認識できていない可能性があります。
    • Content-Type ヘッダーに適切な charset を指定していないため、デフォルトのエンコーディング(通常は ISO-8859-1)で解釈され、文字化けが発生している可能性があります。
  2. HTML コンテンツ自体のエンコーディング:
    • Terraform ファイル内での HTML コンテンツが適切にエンコードされていない場合、文字化けが発生する可能性があります。

解決策

1. Content-Type ヘッダーに charset を追加

aws_api_gateway_integration_response リソースの response_parameters において、Content-Type ヘッダーに charset=utf-8 を追加しました。これにより、ブラウザは受信したコンテンツをUTF-8として解釈します。

response_parameters = {
  "method.response.header.Content-Type" = "'text/html; charset=utf-8'"
}

2. HTML ドキュメントに <meta charset="UTF-8"> を追加

HTML ドキュメントの <head> セクションに <meta charset="UTF-8"> を追加することで、ブラウザに対して文書の文字エンコーディングを明示的に指定しています。

<meta charset="UTF-8">

3. response_models の設定

aws_api_gateway_method_response リソースにおいて、response_models"text/html" = "Empty" と設定しました。これにより、API Gateway は特定のコンテンツタイプに対してモデルを適用しないようになります。

response_models = {
  "text/html" = "Empty"
}

全体のTerraformのコード

locals {
  # ランディングページ用の設定
  landing_page = {
    path_part        = "landing"
    http_method      = "GET"
    response_template = <<EOF
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>ランディングページ</title>
</head>
<body>
    <h1>ようこそ!</h1>
    <p>これはAPI Gatewayのモック統合によるランディングページです。</p>
</body>
</html>
EOF
  }
}

# API Gatewayの作成
resource "aws_api_gateway_rest_api" "landing_api" {
  name        = "LandingPageAPI_Mock"
  description = "Mock API for landing page"
}

# ランディングページ用リソースの作成
resource "aws_api_gateway_resource" "landing_resource" {
  rest_api_id = aws_api_gateway_rest_api.landing_api.id
  parent_id   = aws_api_gateway_rest_api.landing_api.root_resource_id
  path_part   = local.landing_page.path_part
}

# ランディングページ用GETメソッドの作成
resource "aws_api_gateway_method" "landing_method" {
  rest_api_id   = aws_api_gateway_rest_api.landing_api.id
  resource_id   = aws_api_gateway_resource.landing_resource.id
  http_method   = local.landing_page.http_method
  authorization = "NONE"
}

# ランディングページ用モック統合の設定
resource "aws_api_gateway_integration" "landing_integration" {
  rest_api_id             = aws_api_gateway_rest_api.landing_api.id
  resource_id             = aws_api_gateway_resource.landing_resource.id
  http_method             = aws_api_gateway_method.landing_method.http_method
  type                    = "MOCK"
  integration_http_method = "GET"

  request_templates = {
    "application/json" = <<EOF
{
  "statusCode": 200
}
EOF
  }
}

# ランディングページ用メソッドレスポンス (200 OK) の設定
resource "aws_api_gateway_method_response" "landing_method_response_200" {
  rest_api_id = aws_api_gateway_rest_api.landing_api.id
  resource_id = aws_api_gateway_resource.landing_resource.id
  http_method = aws_api_gateway_method.landing_method.http_method
  status_code = "200"

  response_parameters = {
    "method.response.header.Content-Type" = true
  }

  response_models = {
    "text/html" = "Empty"
  }  
}

# ランディングページ用統合レスポンス (200 OK) の設定
resource "aws_api_gateway_integration_response" "landing_integration_response_200" {
  rest_api_id = aws_api_gateway_rest_api.landing_api.id
  resource_id = aws_api_gateway_resource.landing_resource.id
  http_method = aws_api_gateway_method.landing_method.http_method
  status_code = aws_api_gateway_method_response.landing_method_response_200.status_code

  response_templates = {
    "text/html" = local.landing_page.response_template
  }

  response_parameters = {
    "method.response.header.Content-Type" = "'text/html; charset=utf-8'"
  }  
}

# デプロイメントの作成
resource "aws_api_gateway_deployment" "landing_deployment" {
  depends_on = [
    aws_api_gateway_integration.landing_integration,
    aws_api_gateway_integration_response.landing_integration_response_200
  ]

  rest_api_id = aws_api_gateway_rest_api.landing_api.id

  triggers = {
    redeployment_resource                 = sha1(jsonencode(aws_api_gateway_resource.landing_resource))
    redeployment_method                   = sha1(jsonencode(aws_api_gateway_method.landing_method))
    redeployment_integration              = sha1(jsonencode(aws_api_gateway_integration.landing_integration))
    redeployment_method_response          = sha1(jsonencode(aws_api_gateway_method_response.landing_method_response_200))
    redeployment_integration_response     = sha1(jsonencode(aws_api_gateway_integration_response.landing_integration_response_200))
  }

  lifecycle {
    create_before_destroy = true
  }
}

# ステージの作成
resource "aws_api_gateway_stage" "landing_stage" {
  deployment_id = aws_api_gateway_deployment.landing_deployment.id
  rest_api_id   = aws_api_gateway_rest_api.landing_api.id
  stage_name    = "dev"
}

# エンドポイントURLの出力
output "landing_page_endpoint" {
  value = "${aws_api_gateway_stage.landing_stage.invoke_url}/${local.landing_page.path_part}"
}


Shikoan's ML Blogの中の人が運営しているサークル「じゅ~しぃ~すくりぷと」の本のご案内

技術書コーナー

北海道の駅巡りコーナー


Add a Comment

メールアドレスが公開されることはありません。 が付いている欄は必須項目です