AWS CloudFormation が Amazon API Gateway をサポートしたので使ってみた

API Gateway

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

CloudFormation が API Gateway をサポート

先日(2016/04/18) AWS CloudFormation (以下 CloudFormation) がアップデートされ、新たに Amazon API Gateway (以下 API Gateway) がサポートされました。

このアップデートにより、API Gateway の API の詳細な設定を CloudFormation Template で定義・展開できるようになりました。今までは Management Console でポチポチと設定を行う必要がありましたが、CloudFormation のサポートによって、非常に手軽に管理できるようになりました。

本記事では CloudFormation で API Gateway を扱う方法について解説します。

定義可能なリソースタイプ

CloudFormation Template では新たに API Gateway に関するリソースタイプを定義できるようになりました。下記に、定義可能なリソースタイプと意味をまとめてみました。

AWS Resource Type 説明
AWS::ApiGateway::Account CloudWatch Logs にログを送信するために使用する IAM Role の指定
AWS::ApiGateway::ApiKey 各 Stage に対応する API Key の定義
AWS::ApiGateway::Authorizer カスタム認証の設定
AWS::ApiGateway::BasePathMapping API の Stage とドメイン・パスのマッピング
AWS::ApiGateway::ClientCertificate API Gateway から SSL 認証が必要なエンドポイントにリクエストを送信するための設定
AWS::ApiGateway::Deployment Stage へのデプロイの実施
AWS::ApiGateway::Method API のメソッドの定義
AWS::ApiGateway::Model API のモデルの定義
AWS::ApiGateway::Resource API のリソースの定義
AWS::ApiGateway::RestApi API の定義
AWS::ApiGateway::Stage Stage の定義

2月に追加された新機能である「カスタム認証」もバッチリサポートしています。なお Swagger を使いたい場合は事前に S3 にアップロードしておく必要があります。

CloudFormation Template を書いてみる

各リソースタイプの定義の記述方法は、上記の各リソースタイプのドキュメントに個別にサンプルが載っています。そちらを参考に、CloudFormation Template を書いてみました。

まずはシンプルな例から。

  • API SampleAPI を作成
  • Resource SampleResource を作成 (パスは /sample)
  • GET の Mock Method を作成 (ステータスコード 200 を返す)

上記3つのリソースを定義したのが、下記のテンプレートです。

{
  "AWSTemplateFormatVersion" : "2010-09-09",
  "Resources" : {
    "SampleRestApi" : {
      "Type" : "AWS::ApiGateway::RestApi",
      "Properties" : {
        "Description" : "This is Sample Rest API",
        "Name" : "Sample"
      }
    },
    "SampleResource" : {
      "Type": "AWS::ApiGateway::Resource",
      "Properties": {
        "RestApiId" : { "Ref": "SampleRestApi" },
        "ParentId" : { "Fn::GetAtt": ["SampleRestApi", "RootResourceId"] },
        "PathPart": "sample"
      }
    },
    "SampleMethod" : {
      "Type" : "AWS::ApiGateway::Method",
      "Properties" : {
        "RestApiId" : { "Ref" : "SampleRestApi" },
        "ResourceId" : { "Ref" : "SampleResource" },
        "HttpMethod" : "GET",
        "AuthorizationType" : "NONE",
        "Integration" : { 
          "Type" : "MOCK",
          "RequestTemplates" : {
            "application/json": "{ \"statusCode\" : 200 }"
          },
          "IntegrationResponses" : [
            { "StatusCode" : "200" }
          ]
        },
        "MethodResponses" : [ 
          { "StatusCode" : "200" }
        ]
      }
    }
  }
}

このテンプレートで Create Stack してみましょう。AWS CLI から行います。

$ aws cloudformation create-stack --stack-name APIGatewayStack --template-body file://apigateway.json --region ap-northeast-1
{
    "StackId": "arn:aws:cloudformation:ap-northeast-1:xxxxxxxxxxxx:stack/APIGatewayStack/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}

ap-northeast-1 を指定するとリソースが ap-northeast-1 に作成されます。

cfn-api-gateway-01

API Gateway の Management Console で見てみましょう。Method までテンプレート通りに作成されていることが確認できます。

cfn-api-gateway-02

CloudFormation でデプロイまで行う

API や Method の定義だけではなく、 Stage へのデプロイを行うこともできます。

注意点があり、 AWS::ApiGateway::Stage AWS::ApiGateway::Deployment の定義を AWS::ApiGateway::Method と同一の Stack で定義してしまうと AWS::ApiGateway::Method が最後に実行されてしまうため、 Stage 作成時に Method が無いというエラーが発生してしまいます。そのため、次のいずれかを適用する必要があります。

  • DependsOn 属性を使って AWS::ApiGateway::Method を優先的に作成させる
  • AWS::ApiGateway::Method までのテンプレートをネストさせる

それぞれ、定義する方法を紹介します。

DependsOn 属性を使って AWS::ApiGateway::Method を優先的に作成させる

CloudFormation では DependsOn 属性をリソースに追加することで、依存関係を明示することができます。この属性を使って AWS::ApiGateway::Method のリソースを優先的に作成させることができます *1

{
  "AWSTemplateFormatVersion" : "2010-09-09",
  "Resources" : {
    "SampleRestApi" : {
      "Type" : "AWS::ApiGateway::RestApi",
      "Properties" : {
        "Description" : "This is Sample Rest API",
        "Name" : "Sample"
      }
    },
    "SampleResource" : {
      "Type": "AWS::ApiGateway::Resource",
      "Properties": {
        "RestApiId" : { "Ref": "SampleRestApi" },
        "ParentId" : { "Fn::GetAtt": ["SampleRestApi", "RootResourceId"] },
        "PathPart": "sample"
      }
    },
    "SampleMethod" : {
      "Type" : "AWS::ApiGateway::Method",
      "Properties" : {
        "RestApiId" : { "Ref" : "SampleRestApi" },
        "ResourceId" : { "Ref" : "SampleResource" },
        "HttpMethod" : "GET",
        "AuthorizationType" : "NONE",
        "Integration" : { 
          "Type" : "MOCK",
          "RequestTemplates" : {
            "application/json": "{ \"statusCode\" : 200 }"
          },
          "IntegrationResponses" : [
            { "StatusCode" : "200" }
          ]
        },
        "MethodResponses" : [ 
          { "StatusCode" : "200" }
        ]
      }
    },
    "SampleDeployment" : {
      "Type" : "AWS::ApiGateway::Deployment",
      "DependsOn" : "SampleMethod",
      "Properties" : {
        "Description" : "This is Sample Deployment",
        "RestApiId" : { "Ref" : "SampleRestApi" },
        "StageName" : "prd",
        "StageDescription" : {
          "Description" : "Prod Stage",
          "MethodSettings" : [{
            "ResourcePath" : "/sample",
            "HttpMethod" : "GET",
            "MetricsEnabled" : "true",
            "DataTraceEnabled" : "true"
          }]
        }
      }
    }
  }
}

AWS::ApiGateway::Method までのテンプレートをネストさせる

AWS::CloudFormation::Stack を使って、テンプレートの中に Stack をネストさせることができます。ネストされた側の Stack が先に作成されるため AWS::ApiGateway::Method を優先して作成することができます。

まずは上記と同じような定義のテンプレートに Outputs を追加し AWS::ApiGateway::RestApi が参照できるようにします。

{
  "AWSTemplateFormatVersion" : "2010-09-09",
  "Resources" : {
    "SampleRestApi" : {
      "Type" : "AWS::ApiGateway::RestApi",
      "Properties" : {
        "Description" : "This is Sample Rest API",
        "Name" : "Sample"
      }
    },
    "SampleResource" : {
      "Type": "AWS::ApiGateway::Resource",
      "Properties": {
        "RestApiId" : { "Ref": "SampleRestApi" },
        "ParentId" : { "Fn::GetAtt": ["SampleRestApi", "RootResourceId"] },
        "PathPart": "sample"
      }
    },
    "SampleMethod" : {
      "Type" : "AWS::ApiGateway::Method",
      "Properties" : {
        "RestApiId" : { "Ref" : "SampleRestApi" },
        "ResourceId" : { "Ref" : "SampleResource" },
        "HttpMethod" : "GET",
        "AuthorizationType" : "NONE",
        "Integration" : { 
          "Type" : "MOCK",
          "RequestTemplates" : {
            "application/json": "{ \"statusCode\" : 200 }"
          },
          "IntegrationResponses" : [
            { "StatusCode" : "200" }
          ]
        },
        "MethodResponses" : [ 
          { "StatusCode" : "200" }
        ]
      }
    }
  },
  "Outputs" : {
    "RestApiId" : {
      "Value" : { "Ref" : "SampleRestApi" }
    }
  }
}

このテンプレートを S3 にアップロードした後、下記のテンプレートにネストさせます。

{
  "AWSTemplateFormatVersion" : "2010-09-09",
  "Resources" : {
    "SampleStack" : {
      "Type": "AWS::CloudFormation::Stack",
      "Properties" : {
        "TemplateURL" : "https://s3-ap-northeast-1.amazonaws.com/xxxxx/api-gateway.template"
      }
    },
    "SampleDeployment" : {
      "Type" : "AWS::ApiGateway::Deployment",
      "Properties" : {
        "Description" : "This is Sample Deployment",
        "RestApiId" : { "Fn::GetAtt" : [ "SampleStack", "Outputs.RestApiId" ] },
        "StageName" : "prd",
        "StageDescription" : {
          "Description" : "Prod Stage",
          "MethodSettings" : [{
            "ResourcePath" : "/sample",
            "HttpMethod" : "GET",
            "MetricsEnabled" : "true",
            "DataTraceEnabled" : "true"
          }]
        }
      }
    }
  }
}

これで Create Stack すると 2 つの Stack が作成されます。

cfn-api-gateway-03

prd という Stage が作成されました。

cfn-api-gateway-04

まとめ

API Gateway は扱うリソースが多いため、Management Console で作っていくのは地味に時間がかかる面倒な作業でした。CloudFormation 対応は喜ばしい限りですね。

AWS Lambda も既にサポートされていますので、AWS のサーバーレスの代名詞とも言える API Gateway + Lambda の組み合わせも CloudFormation で定義できるようになりました。

サーバーレスアーキテクチャのリソースも CloudFormation でしっかり管理しましょう!

参考

脚注

  1. こちらを見て ( ゚д゚)ハッ! っとなり追記しました。