aws-cdk apigateway lambda cors対応

aws-cdkのApigateway&LambdaでCORS対応で詰まったのでメモ。OriginやMethodは適宜修正してください。

  • resourceにdefaultCorsPreflightOptionsを渡す
  • lambda内で必要なheaderを設定する

フォルダ構成

バージョン

package.json

{
  "name": "cdk-test",
  "version": "0.1.0",
  "bin": {
    "cdk-test": "bin/cdk-test.js"
  },
  "scripts": {
    "build": "tsc",
    "watch": "tsc -w",
    "test": "jest",
    "cdk": "cdk"
  },
  "devDependencies": {
    "@aws-cdk/assert": "1.95.1",
    "@types/aws-lambda": "^8.10.73",
    "@types/aws-sdk": "^2.7.0",
    "@types/jest": "^26.0.10",
    "@types/node": "10.17.27",
    "aws-cdk": "1.95.1",
    "esbuild": "0",
    "jest": "^26.4.2",
    "ts-jest": "^26.2.0",
    "ts-node": "^9.0.0",
    "typescript": "~3.9.7"
  },
  "dependencies": {
    "@aws-cdk/aws-apigateway": "^1.95.1",
    "@aws-cdk/aws-lambda": "^1.95.1",
    "@aws-cdk/aws-lambda-nodejs": "^1.95.1",
    "@aws-cdk/core": "1.95.1",
    "source-map-support": "^0.5.16"
  }
}

スタック

cdk-test-stack.ts

import * as cdk from "@aws-cdk/core";
import * as apigateway from "@aws-cdk/aws-apigateway";
import * as lambda from "@aws-cdk/aws-lambda";
import { NodejsFunction } from "@aws-cdk/aws-lambda-nodejs";
export class CdkTestStack extends cdk.Stack {
  constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // The code that defines your stack goes here
    const prefix = "Playground";

    const api = new apigateway.RestApi(this, `${prefix}-Api`, {
      restApiName: `${prefix}-Api`,
    });
    api.root.addMethod("ANY");

    const lambdaFunction = new NodejsFunction(
      this,
      `${prefix}-lambdaFunction`,
      {
        functionName: `${prefix}-hello`,
        runtime: lambda.Runtime.NODEJS_14_X,
        entry: "lambda/hello.ts",
        handler: "handler",
      }
    );

    const integration = new apigateway.LambdaIntegration(lambdaFunction);

    const resource = api.root.addResource("user", {
      defaultCorsPreflightOptions: {
        allowOrigins: apigateway.Cors.ALL_ORIGINS,
        allowMethods: apigateway.Cors.ALL_METHODS,
        allowHeaders: apigateway.Cors.DEFAULT_HEADERS,
        disableCache: true,
      },
    });
    const getMethod = resource.addMethod("GET", integration);
    const patchMethod = resource.addMethod("PATCH", integration);
  }
}

Lambda

hello.ts

import {
  APIGatewayEventRequestContext,
  APIGatewayProxyEvent,
  APIGatewayProxyResult,
} from "aws-lambda";

export const handler = async (
  event: APIGatewayProxyEvent,
  context: APIGatewayEventRequestContext
): Promise => {
  return {
    statusCode: 200,
    headers: {
      "Access-Control-Allow-Origin": "*",
      "Access-Control-Allow-Methods": "OPTIONS,GET,PUT,POST,DELETE,PATCH,HEAD",
      "Access-Control-Allow-Headers":
        "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token,X-Amz-User-Agent'",
    },
    body: JSON.stringify({
      message: "Hello World",
      method: event.httpMethod,
      query: event.queryStringParameters,
      path: event.path,
      pathParameters: event.pathParameters,
      context,
    }),
  };
};