【AWS】IDE上からSAMでLambda×APIGatewayを実装する備忘録
はじめに
本記事は備忘録としてのwikiです。
各ファイルの役割や記載内容の詳しい説明は割愛しております。
本記事内では以下の2点を行います。
- TypeScriptでサーバーレスのAPI環境を構築します。
- その環境に対して任意のAPIを実装します。
※ 最終的なyml全文は『最後に』の追記後を参照してください。
環境
使用IDE
IntelliJ WebStorm
(私は未確認だが無料の『IntelliJ IDEA CE』でも同じ操作感のはず)
→ IntelliJ IDEA CEは対応していなかったです。。。
OS
Mac 14.3
前提
- AWSDevelopperのアカウントを既に作成している
- IDEに対してAWSアカウントの認証が許可されている
理解の助けになる知識
LambdaとAPIGatewayについてのある程度の理解
RESTAPIについてのある程度の理解
AWSのマイクロサービス等の構成についての理解
.ymlファイルの構文を知っている
手順
- 自分のマシンにsamをインストールする
- IDEで新しいAWSサーバーレスアプリのプロジェクトを作成する
- デプロイを実行する
- 自分の任意のAPIを作成する
- 更新のデプロイを実行する
1.自分のマシンにsamをインストールする
公式にインストーラがあるのでそこからとってくる。
各OSに合ったものが用意されているのでインストールする。2.IDEで新しいAWSサーバーレスアプリのプロジェクトを作成する
公式に書いてある通りです。
以下のキャプチャ画像の通りに設定していきます。
SAMのパスが設定されていないと先に進めないので、
設定されていない場合は以下の方法で設定を済ませてください。
既にパスが設定されている場合は『create』を押してプロジェクトを作成してください。
samの実行パスを設定する
SAM CLI excutable:の項目にパスを設定します。
パスはMacの場合、whichコマンドで取得できます。
which sam
3. デプロイを実行する
プロジェクトが作成されたらデフォルトでディレクトリが構成されています。
デフォルトではHelloWorldAPIが実装されます。
まずはデフォルトの挙動を見るために、READMEに従ってデプロイを完了させます。
以下のコマンドはすべてプロジェクトルートの階層で実行します。
ローカル用でのデプロイ方法などもREADMEに記載されているので、目を通しておくといいです。
今回は普通にビルドします。
ビルド
sam build
デプロイ
--guided
によって対話形式で環境変数を設定してデプロイができます。
sam deploy --guided
完了したら、stackという単位でAWS環境が構築されます。
実際にブラウザでAWSのコンソール画面にアクセスして『CloudFormation』を確認してみると、
新しくstackが作成されていることが確認できます。
4. 自分の任意のAPIを作成する
最終的なyml全文は『最後に』の追記後を参照してください。
template.yamlを編集する
デフォルトで書かれているHelloWorldFunction
のブロックの下に以下を追加する。
MyCustomFunction: # 新しく追加したLambda関数
Type: AWS::Serverless::Function
Properties:
CodeUri: hello-world/ # TypeScriptのソースのパス
Handler: app.myCustomFunctionHandler # 任意のモジュール
Runtime: nodejs18.x
Architectures:
- x86_64
Events:
MyCustomEndpoint:
Type: Api
Properties:
Path: /MyCustomFunction
Method: get # 任意のHTTPメソッド
Metadata:
BuildMethod: esbuild
BuildProperties:
Minify: true
Target: "es2020"
Sourcemap: true
EntryPoints:
- app.ts
app.tsxにコードを追加する
your-aws-project/hello-world/app.tsx
にTypeScriptのコードを追記する。
これはLambda関数の『コード』にあたる、いわゆる処理の部分。
myCustomFunctionHandler
としてエクスポートする。
以下のコードを記述。
めんどくさかったので、デフォルトのHelloWorldのコピペですが。。。(レスポンスの文字列だけ変えたよ)
export const myCustomFunctionHandler = async (event: APIGatewayProxyEvent): Promise<APIGatewayProxyResult> => {
try {
return {
statusCode: 200,
body: JSON.stringify({
message: 'this is my function',
}),
};
} catch (err) {
console.log(err);
return {
statusCode: 500,
body: JSON.stringify({
message: 'some error happened',
}),
};
}
};
test-handler.test.tsにテストを追加する
your-aws-project/hello-world/tests/unit/test-handler.test.ts
にテストを追加する
めんどくさかったので、デフォルトのHelloWorldのコピペですが。。。(実際はちゃんと書いてね)
it('verifies successful response', async () => {
const event: APIGatewayProxyEvent = {
httpMethod: 'get',
body: '',
headers: {},
isBase64Encoded: false,
multiValueHeaders: {},
multiValueQueryStringParameters: {},
path: '/hello',
pathParameters: {},
queryStringParameters: {},
requestContext: {
accountId: '123456789012',
apiId: '1234',
authorizer: {},
httpMethod: 'get',
identity: {
accessKey: '',
accountId: '',
apiKey: '',
apiKeyId: '',
caller: '',
clientCert: {
clientCertPem: '',
issuerDN: '',
serialNumber: '',
subjectDN: '',
validity: { notAfter: '', notBefore: '' },
},
cognitoAuthenticationProvider: '',
cognitoAuthenticationType: '',
cognitoIdentityId: '',
cognitoIdentityPoolId: '',
principalOrgId: '',
sourceIp: '',
user: '',
userAgent: '',
userArn: '',
},
path: '/hello',
protocol: 'HTTP/1.1',
requestId: 'c6af9ac6-7b61-11e6-9a41-93e8deadbeef',
requestTimeEpoch: 1428582896000,
resourceId: '123456',
resourcePath: '/hello',
stage: 'dev',
},
resource: '',
stageVariables: {},
};
const result: APIGatewayProxyResult = await myCustomFunctionHandler(event);
expect(result.statusCode).toEqual(200);
expect(result.body).toEqual(
JSON.stringify({
message: 'hello world',
}),
);
});
5. 更新のデプロイを実行する
プロジェクトルートの階層で次のコマンドを実行する。
sam deploy cloudformation deploy --template-file ./template.yaml --stack-name your-aws-project --capabilities CAPABILITY_IAM
各オプションの意味は以下の通り。
--stack-name
にはすでにデプロイ済みのスタック名を指定する。
これで既にあるstackの更新だと認識される。
--template-file
にはtemplateファイルのパスを渡す。
--capabilities CAPABILITY_IAM
でIAMリソースの変更を許可する。
これでAPIの実装は完了。
最後に
オーソライザーの設定の仕方やCORS対応などもSAMで行っていきたい。
---追記---
同じエンドポイント上に異なるメソッド(GETとかOPTIONSとか)を設定していくうえで以下のような書き方になりました。
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
your-aws-project
Sample SAM Template for your-aws-project
# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst
Globals:
Function:
Timeout: 3
Resources:
MyApiGateway:
Type: AWS::Serverless::Api
Properties:
StageName: Dev
DefinitionBody:
swagger: '2.0'
info:
title: your-aws-project
version: '1.0'
paths:
/MyCustomFunction:
# OPTIONSメソッド
options:
summary: OPTIONS Method
responses:
'200':
description: 200 response
x-amazon-apigateway-integration:
type: mock
requestTemplates:
application/json: '{"statusCode": 200}'
responses:
default:
statusCode: 200
# GETメソッド
get:
responses:
'200':
description: 200 response
x-amazon-apigateway-integration:
type: aws_proxy # Lambda統合
uri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyCustomFunction.Arn}/invocations # Lambda関数との紐付け
httpMethod: GET
/hello:
get:
responses:
'200':
description: 200 response
x-amazon-apigateway-integration:
type: aws_proxy
uri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HelloWorldFunction.Arn}/invocations
httpMethod: GET
HelloWorldFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: hello-world/
Handler: app.lambdaHandler
Runtime: nodejs18.x
Architectures:
- x86_64
Events:
HelloWorld:
Type: Api
Properties:
Path: /hello
Method: get
RestApiId: !Ref MyApiGateway
MyCustomFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: hello-world/
Handler: app.myCustomFunctionHandler
Runtime: nodejs18.x
Architectures:
- x86_64
Events:
MyCustomEndpoint:
Type: Api
Properties:
Path: /MyCustomFunction
Method: get
RestApiId: !Ref MyApiGateway
Discussion