API Gateway+LambdaなCloudFormationテンプレートを作る
CloudFormationテンプレートは少し苦手意識があるのですが、会社の勉強会で取り上げようと思ったので頑張って作りました。
Lambda関数
まずLambda関数を作ります。勉強会用のサンプルなのでとても適当です。APIからAPIを呼んでるだけの意味のないコードですが、中身が本質ではないので許してください。
ちなみにnode-fetchは外部パッケージなのでnpm installが必要です。
const fetch = require('node-fetch');
exports.handler = async (event) => {
console.log(event);
const pathParams = event.pathParameters;
const isbn = pathParams.isbn;
const url = "http://api.openbd.jp/v1/get?isbn=" + isbn;
const res = await fetch(url);
const data = await res.json();
const response = {
statusCode: 200,
body: JSON.stringify(data),
};
return response;
};
これを、Lambda関数ページの「アクション」⇒「関数のエクスポート」でZipファイル化します。そして、Zipファイルを適当なS3バケットにアップロードします。
これでLambdaの準備は完了です。
CloudFormationテンプレートファイルを作る
テンプレートファイルの完成形は以下になります。
AWSTemplateFormatVersion: '2010-09-09'
Parameters:
FunctionName:
Type: String
Description: "Please enter function name"
Resources:
# Lambda
Lambda:
Type: 'AWS::Lambda::Function'
Properties:
Code:
S3Bucket: "********"
S3Key: !Sub "********.zip"
Description: "Lambda function to get informations of books"
FunctionName: !Sub ${FunctionName}
Handler: index.handler
Runtime: nodejs16.x
MemorySize: 128
Timeout: 10
Role: !Sub arn:aws:iam::${AWS::AccountId}:role/lambda-basic-policy
# API Gateway
ApiGW:
Type: 'AWS::ApiGateway::RestApi'
Properties:
Name: "openbd-api"
ApiBooksResource:
Type: 'AWS::ApiGateway::Resource'
Properties:
RestApiId: !Ref ApiGW
ParentId: !GetAtt ApiGW.RootResourceId
PathPart: 'books'
DependsOn:
- ApiGW
- Lambda
ApiIsbnResource:
Type: 'AWS::ApiGateway::Resource'
Properties:
RestApiId: !Ref ApiGW
ParentId: !Ref ApiBooksResource
PathPart: '{isbn}'
DependsOn:
- ApiBooksResource
LambdaPermission:
Type: 'AWS::Lambda::Permission'
Properties:
FunctionName: !Sub ${FunctionName}
Action: 'lambda:InvokeFunction'
Principal: 'apigateway.amazonaws.com'
DependsOn:
- ApiIsbnResource
ResourceMethod:
Type: 'AWS::ApiGateway::Method'
Properties:
RestApiId: !Ref ApiGW
ResourceId: !Ref ApiIsbnResource
AuthorizationType: 'None'
HttpMethod: 'GET'
Integration:
Type: 'AWS_PROXY'
IntegrationHttpMethod: 'POST'
Uri: !Sub 'arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:${FunctionName}/invocations'
DependsOn: 'LambdaPermission'
どういうテンプレートかというと、S3に置いてあるZipファイルを元にLambda関数を作成し、API Gatewayに接続するということをやっています。
***になっている部分は、適当に自分の環境に置き換えてください。
いくつかポイントがあります。
①Lambdaのロール
LambdaにIAMロールのARNが設定してありますが、これはあらかじめ作っておきます。ロールの内容はAWSLambdaBasicExecutionRoleがついていればOKです。
②API Gatewayのリソースパス
今回、APIをhttps://***/books/{isbn}というURLにしました。そのため、まずAPI本体を作り、次にbooksというリソースを作り、その下に{isbn}というリソースを作るといった構成になっています。
最後にメソッドを作っていますが、{isbn}に対してGETメソッドを定義しています。
③依存関係
Lambdaよりも先にAPI Gatewayがデプロイされてしまうと、接続先のLambdaがないので404エラーとなります。そこで、DependsOnパラメータによってデプロイの順番を制御しています。
まとめ
CDKと比べてCloudFormationのテンプレートは難しいです。もう幾度となくエラーを出しまくって試行錯誤の末にようやく完成できました。
今後もIaCはCDKをメインに使っていくと思いますが、CloudFormationも知識として知っておかなければならないと思うので、良い機会でした。