概要
APIGatewayからLambdaを呼び出せるようにするまでの設定をaws-sdk
を使って自動化したかったのでコードを書いてみました。
特に CORS の有効化の部分はなかなか資料がなく苦労しました。。。
TypeScriptで書いているので型定義不要な方は適時読み替えてください。
上から順につなげれば動きます。
実装コード
REST API の作成
import AWS from "aws-sdk";
AWS.config.update({
region: "ap-northeast-1",
accessKeyId: "XXXXXXXXXXXXXXXXXXX",
secretAccessKey: "XXXXXXXXXXXXXXXXXXXXXX",
});
// APIGateway
const apiGateway = new AWS.APIGateway();
/**
* REST APIを作成する
* @param apiName ステージ名
* @return REST APIのID
*/
const createRestApi = async (apiName: string): Promise<string> => {
// REST APIを作成する
const result = await apiGateway.createRestApi({ name: apiName }).promise();
// REST APIのIDを記録しておく
const restApiId = result.id;
return restApiId;
};
リソースの作成
/**
* REST APIのリソースを作成する
* @param restApiId REST APIのID
* @param parentPath 親リソースのパス
* @param pathPart リソースパス
* @return Lambda設定
*/
const createRestApiResource = async (restApiId: string, parentPath: string, pathPart: string): Promise<string> => {
// 親リソースのID
let parentResourceId: string | undefined = "";
// リソース一覧を取得する
const getResourcesResult = await apiGateway.getResources({ restApiId }).promise();
if (getResourcesResult.items) {
// 見つかったリソースでループする
for (const resource of getResourcesResult.items) {
if (resource.path === parentPath) {
// 親リソースのIDを取得する
parentResourceId = resource.id;
break;
}
}
}
if (!parentResourceId) {
// 親リソースが見つからなければエラー
throw new Error(`親リソース:${parentPath} が見つかりませんでした。`);
}
// 親リソースが見つかれば、そこにリソースを追加する
const result = await apiGateway
.createResource({
restApiId: restApiId,
parentId: parentResourceId,
pathPart: pathPart,
})
.promise();
// 作成したリソースのIDを取得する
const resourceId = result.id;
return resourceId;
};
CORS の有効化 (OPTION メソッドの追加)
/**
* REST APIのリソースにOPTIONメソッドを作成する
* @param restApiId REST APIのID
* @param resourceId リソースのID
*/
export const createRestApiOptionMethod = async (restApiId: string, resourceId: string) => {
// OPTIONSメソッドを作成する
await apiGateway
.putMethod({
restApiId: restApiId,
resourceId: resourceId,
httpMethod: "OPTIONS",
authorizationType: "NONE",
})
.promise();
// メソッドレスポンスを作成する
await apiGateway
.putMethodResponse({
restApiId: restApiId,
resourceId: resourceId,
httpMethod: "OPTIONS",
statusCode: "200",
responseParameters: {
"method.response.header.Access-Control-Allow-Headers": false,
"method.response.header.Access-Control-Allow-Methods": false,
"method.response.header.Access-Control-Allow-Origin": false,
},
})
.promise();
// 統合リクエストを作成する
await apiGateway
.putIntegration({
restApiId: restApiId,
resourceId: resourceId,
httpMethod: "OPTIONS",
integrationHttpMethod: "OPTIONS",
type: "MOCK",
contentHandling: "CONVERT_TO_TEXT",
requestTemplates: {
"application/json": '{"statusCode": 200}',
},
})
.promise();
// 統合レスポンスを作成する
await apiGateway
.putIntegrationResponse({
restApiId: restApiId,
resourceId: resourceId,
httpMethod: "OPTIONS",
statusCode: "200",
responseParameters: {
"method.response.header.Access-Control-Allow-Headers": "'Content-Type,Authorization,X-Amz-Date,X-Api-Key,X-Amz-Security-Token'",
"method.response.header.Access-Control-Allow-Methods": "'DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT'",
"method.response.header.Access-Control-Allow-Origin": "'*'",
},
})
.promise();
};
メソッドを追加して Lambda を呼び出すようにする
/**
* REST APIのリソースにPOSTメソッドを作成する
* @param restApiId REST APIのID
* @param resourceId リソースのID
* @param httpMethod メソッド名
* @param lambdaArn 呼び出すLambdaのARN
*/
export const createRestApiPostMethod = async (restApiId: string, resourceId: string, httpMethod: string, lambdaArn: string) => {
// メソッドを作成する
await apiGateway.putMethod({ restApiId, resourceId, httpMethod: httpMethod, authorizationType: "NONE" }).promise();
// 統合リクエストを作成する
await apiGateway
.putIntegration({
restApiId: restApiId,
resourceId: resourceId,
httpMethod: httpMethod,
integrationHttpMethod: httpMethod,
type: "AWS_PROXY", // Lambdaプロキシ統合の使用
contentHandling: "CONVERT_TO_TEXT",
uri: `arn:aws:apigateway:${AWS.config.region}:lambda:path/2015-03-31/functions/${lambdaArn}/invocations`,
})
.promise();
};
デプロイする
/**
* REST APIをデプロイする
* @param restApiId APIのID
* @param stageName ステージ名
*/
const deployRestApi = async (restApiId: string, stageName: string) => {
await apiGateway.createDeployment({ restApiId, stageName: stageName }).promise();
};
使用例
(async () => {
// LambdaのARNは事前に分かっているものとする
const lambdaArn = "arn:aws:lambda:ap-northeast-1:XXXXXXXXX:function:YYYYYYYYYYY";
// REST APIを作成する
const restApiId = await createRestApi("test-api");
// hogeリソースを作成する
const resourceId = await createRestApiResource(restApiId, "/", "hoge");
// hogeリソースのCORSを有効化する (OPTIONSメソッドを作成)
await createRestApiOptionMethod(restApiId, resourceId);
// hogeリソースにPOSTメソッドを作成し、Lambdaを呼び出すようにする
await createRestApiPostMethod(restApiId, resourceId, "POST", lambdaArn);
// ステージ:dev としてデプロイする
await deployRestApi(restApiId, "dev");
})();