Subscribed unsubscribe Subscribe Subscribe

CloudFormationでAPIGatewayのCORSを有効にするには

サーバーレスアーキテクチャの実現にはEC2やECSを使用せずに、S3上のJSからApiGatewayにアクセスできるないといけません。 するとおのずと、ApiGatewayに作成したAPIにCORSを有効にする必要があります。

AWSを使うなら、ちゃんとCloudFormationを使ってインフラをソースで管理するのがよいと思います。
本番のアプリケーションのソースをリビジョン管理せずに直接修正しないのと同じです。
似たような仕組みを作るのに数ヶ月ではなく、10分程度で作れるので、手間がかからず、効率的です。
インフラのリファクタや刷新も楽にできます。

ApiGatewayにCORSを設定していきます。

CORSを有効にする際に必要な設定

コンソールから設定する場合

コンソールから設定する場合に表示される内容

Create OPTIONS method
Add 200 Method Response with Empty Response Model to OPTIONS method
Add Mock Integration to OPTIONS method
Add 200 Integration Response to OPTIONS method
Add Access-Control-Allow-Headers, Access-Control-Allow-Methods, Access-Control-Allow-Origin Method Response Headers to OPTIONS method
Add Access-Control-Allow-Headers, Access-Control-Allow-Methods, Access-Control-Allow-Origin Integration Response Header Mappings to OPTIONS method
Add Access-Control-Allow-Origin Method Response Header to POST method
Add Access-Control-Allow-Origin Integration Response Header Mapping to POST method
Add Access-Control-Allow-Origin Method Response Header to GET method
Add Access-Control-Allow-Origin Integration Response Header Mapping to GET method

Access-Control-Expose-Headers(カンマ区切りの許可するブラウザ), Access-Control-Max-Age(preflightリクエストのキャッシュ秒), Access-Control-Allow-Credentials(credentialsでのアクセス許可をする場合はtrue)はオプションです。

設定される内容

  • OPTIONSメソッド
Mock Endpoint
  • Method Request
  • Integration Request
Type: MOCK

Request body paththrough
→When no template matches the request Content-Type header

Content-Type: application/json
  • Integration Response
Method response status: 200
Default mapping: true

Header Mappings
Access-Control-Allow-Headers: 'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'
Access-Control-Allow-Methods: 'POST,GET,OPTIONS'
Access-Control-Allow-Origin: '*'

Content-Type: application/json

Output passthrough: Yes
  • Method Response
HTTP Status: 200

Response Headers for 200
Access-Control-Allow-Headers
Access-Control-Allow-Methods
Access-Control-Allow-Origin

Response Body for 200
Content type: application/json
Models: Empty

上記を実現するyaml

  ${path}OptionsMethod:
    Type: AWS::ApiGateway::Method
    Properties:
      AuthorizationType: NONE
      HttpMethod: OPTIONS
      ResourceId:
        !Ref ${path}Resource
      RestApiId:
        !ImportValue RestApi
      Integration:
        Type: MOCK
        PassthroughBehavior: WHEN_NO_TEMPLATES
        RequestTemplates:
          application/json: "{\"statusCode\" : 200}"
        IntegrationResponses:
          - StatusCode: 200
            ResponseTemplates:
              application/json: "$input.body"
            ResponseParameters:
              method.response.header.Access-Control-Allow-Methods: "'GET,POST,OPTIONS'"
              method.response.header.Access-Control-Allow-Headers: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'"
              method.response.header.Access-Control-Allow-Origin: !Sub
                - "'http://${Domain}'"
                - { Domain: !ImportValue Domain }
      MethodResponses:
        - ResponseParameters:
            method.response.header.Access-Control-Allow-Methods: true
            method.response.header.Access-Control-Allow-Headers: true
            method.response.header.Access-Control-Allow-Origin: true
          StatusCode: 200

※${path}はAPIのOPTIONSメソッドを追加する対象のパスに変換します
※RestApiはAWS::ApiGateway::RestApiを事前に作成して、Exportしておきます
※${path}ResourceはAWS::ApiGateway::Resourceを事前に作成して、Exportしておきます

実行結果

OPTIONSメソッド

  • Response Body
{}
  • Response Headers
{
  "Access-Control-Allow-Origin":"http://${Domain}",
  "Access-Control-Allow-Methods":"GET,POST,OPTIONS",
  "Access-Control-Allow-Headers":
    "Content-Type,
    X-Amz-Date,
    Authorization,
    X-Api-Key,X-Amz-Security-Token",
  "Content-Type":"application/json"
}

GETメソッド

  • Response Headers
{
  "Access-Control-Allow-Origin":"http://${Domain}",
  "Access-Control-Allow-Methods":"GET,OPTIONS",
  "X-Amzn-Trace-Id":"Root=1-111111111111111111",
  "Access-Control-Allow-Headers":
    "Content-Type,
    X-Amz-Date,
    Authorization,
    X-Api-Key,
    X-Amz-Security-Token",
  "Content-Type":"application/json"
}