🐶

AWS SAMによる、Lambda統合のやり方

2021/11/04に公開

Summary

API Gatewayで受け取ったヘッダー情報をlambdaに流したいという用件があり、lambda統合(lambda integration)をSAMで行うことがあったのでその内容をまとめました。
Originの値を取りたいだとか、lambda側でIP制限を行いたい人とか参考にできるんじゃないかと思っています。

lambda統合とは?

lambda統合を行うことで、API メソッドを Lambda 関数に統合することができます。

前提条件

$ aws --version
aws-cli/2.2.5 Python/3.8.8 Darwin/20.4.0 exe/x86_64 prompt/off

@ sam --version
SAM CLI, version 1.21.1

$ node -v
12.22.1

$  volta  -v 
1.0.2

筆者はバージョン管理の兼ね合いでvoltaを使っていますが、特段入れる必要はありません。voltaをインストールしない場合は、package.json内の"volta": { ... 以下の部分は削除してください。

下準備

AWSのS3のus-east-1のリージョンで適当に名前をつけてバゲットを作成してください。

構成

フォルダ構成

.
├──src
│  └── index.ts 
├── package.json
├── yarn.lock
├── node_modules
├── dist
└── template.yml

template.yml

Corsは*にしています。ここの設定は適宜変えていただけると幸いです。

template.yml

AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'

Globals:
  Api:
    EndpointConfiguration: REGIONAL
    Cors: "'*'"

Resources:
  ExampleFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: index.handler
      Runtime: nodejs12.x
      CodeUri: dist/
      Events:
        Handler:
          Type: Api
          Properties:
            Path: /handler
            Method: get
            RestApiId:
              Ref: ExampleAPIGateway

  ExampleAPIGateway:
    Type: AWS::Serverless::Api
    DependsOn: ExampleFunction
    Properties:
      StageName: prod
      DefinitionBody:
        swagger: 2.0
        info:
          version: "1.0"
          title: "Lambda Integration Example"
        basePath: /prod
        schemes:
        - "https"
        paths:
          /handler:
            get:
              responses: {}
              x-amazon-apigateway-integration:
                uri:
                  Fn::Sub: arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${ExampleFunction.Arn}/invocations
                passthroughBehavior: "when_no_match"
                httpMethod: "POST"
                type: "aws_proxy"

package.json

Summaryでも書きましたが、voltaを使わない人は"volta": {...以下を削除してください。
また、--s3-bucketの部分は下準備で作成したバケットの名前を入れてください。

{
  "name": "lambda-integration-example",
  "version": "1.0.0",
  "description": "Lambda Integration Example for Typescript",
  "main": "index.ts",
  "scripts": {
    "build": "yarn tsc -p ./tsconfig.json && cp ./package.json ./dist/package.json",
    "deploy": "sam deploy  --template-file template.yml --stack-name lambda-integration-example-add-your-name --s3-bucket lambda-integration-example-add-your-name --region us-east-1 --capabilities CAPABILITY_IAM CAPABILITY_NAMED_IAM CAPABILITY_AUTO_EXPAND"
  },
  "dependencies": {
    "aws-lambda": "^1.0.6"
  },
  "devDependencies": {
    "@types/aws-lambda": "^8.10.85",
    "typescript": "^4.4.4"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "volta": {
    "node": "12.22.1",
    "yarn": "1.22.10"
  }
}

index.ts

ここでは、APIを叩いてきた元のIPをbodyに入れてみたいと思います。

index.ts
import { APIGatewayProxyHandler } from 'aws-lambda'

export const handler: APIGatewayProxyHandler =  async(event)  => {
    console.info('headers', event.headers)
    const ip = event.headers['X-Forwarded-For']
    return {
        statusCode: 200,
        body: `IP is ${ip}, and handler is success`,
      }
}

デプロイ

ルートディレクトリで実行してください。

$ yarn build
$ yarn deploy

上のコマンドを実行すると、おそらくAPI GatewayにLambda Integration Exampleという名前でAPI Gatewayが作成されているかと思います。

上の写真のURLの呼び出しと書いている部分にAPI GatewayのURLが生成されるので、下記のようにコマンドを入力してください。

$ curl https://xxxxxxxx.execute-api.us-east-1.amazonaws.com/prod/handler
IP is xxx.xxx.xxx.xxx, and handler is success

上のように呼び出し元のIPが表示されていると成功です。

最後に

lambda統合をSAMで行うという記事を書かせていただきました。
普段はフロントエンドをメインで書いているエンジニアなのですが、最近AWSを使うことが増えてきた&記事を書いてみるということをしてみたかった、のでこの度投稿させて頂きました。
今回初めて記事を書いたので、おそらく読みづらかったりするかもしれませんがそこは悪しからず。。。
今回の記事で使用したコードが含まれているレポジトリを載せておきます。
https://github.com/tabikaeru/lambda-integration-typescript
最後までお読み頂きありがとうございました。もし参考になった、良かったと思われる方はいいねボタンを押していただけると嬉しいです。
Thank you!

Discussion