Perl Hackers Hub

第75回AWS Lambda入門 サーバレスでもPerlを活用しよう!(2)

本連載では第一線のPerlハッカーが回替わりで執筆していきます。今回のハッカーは一野瀬翔吾さんで、テーマは「AWS Lambda入門」⁠2)です。

<前回(1)こちら。>

シンプルなHTTP APIの作成

無事にLambda関数の実行ができましたが、実行するにはマネジメントコンソールかAWS CLIが必要です。これでは気軽に利用できません。そこで、Lambda関数にHTTPエンドポイントを追加して、HTTP APIとして利用できるようにしましょう。

HTTPリクエストを待ち受ける

先ほどのSAMテンプレートに次の❶の設定を追加します。https://xxxxx.lambda-url.ap-northeast-1.on.aws/のようなURLが発行されるので、マネジメントコンソールからURLを確認しておきましょう。

リスト template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
 
Resources:
  Function:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: src
      Handler: handler.handle
      Runtime: provided.al2
      Layers:
        - "arn:aws:lambda:ap-northeast-1:445285296882\ 
          :layer:perl-5-36-runtime-al2-x86_64:1"
          
      # Function URLsを有効化する
      FunctionUrlConfig:               ┼-❶
        AuthType: NONE

HTTPレスポンスを返す

受け取ったHTTPリクエストを処理するには、仕様に沿った形式でLambda関数を実装する必要があります。実装を簡単に行えるよう、AWS::LambdaモジュールにはPSGIPerl Web Server Gateway InterfaceをLambda関数に変換するユーティリティが実装してあります。PSGIはPerlで書かれたWebアプリケーションの呼び出し規約で、多くのPerl製Webフレームワークが対応しています。

例として、⁠hello, world」と返すだけのPSGIアプリケーションをLambda関数に変換してみます。

リスト handler.pl
use v5.36;
use utf8;
use AWS::Lambda::PSGI;

# "hello, world"と返すだけのPSGIアプリケーション
my $app = sub {
    return [
        200,
        ['Content-Type' => 'text/plain'],
        ["hello, world\n"]
    ];
};

# PSGIをAWS Lambda Function URLsに対応した関数に変換
my $func = AWS::Lambda::PSGI->wrap($app);

# アプリケーションを実行
sub handle ($payload, $context) {
    return $func->($payload);
}
1;

APIの動作確認

sam deployを使ってデプロイしましょう。AWSによって発行されたURLにアクセスすると、⁠hello, world」という文字列が表示されます。

$ sam deploy
$ curl https://xxxxx.lambda-url.ap-northeast-1.on.aws/
hello, world

ほかのAWSサービスとの連携

最後にAWSサービスとの連携を試してみましょう。連携するサービスにはDynamoDBを使用し、APIへのアクセス数をカウントするカウンタを作ってみます。

DynamoDBのテーブルの作成

DynamoDBはAWSが提供するkey-value形式のデータベースです。リレーショナルデータベースのような複雑な集計処理はできませんが、単純なデータの保存なら手軽に扱えます。DynamoDBを扱うための設定をSAMテンプレートに追記しましょう。

リスト template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
 
Resources:
  # DynamoDBのテーブルを作成
  Table:                                ┼ー❶
    Type: AWS::Serverless::SimpleTable
    
  Function:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: src
      Handler: handler.handle
      Runtime: provided.al2
      Layers:
        - "arn:aws:lambda:ap-northeast-1:445285296882\ 
          :layer:perl-5-36-runtime-al2-x86_64:1"
          
        # コンパイル済みのAWS SDK for Perlを読み込み
        - "arn:aws:lambda:ap-northeast-1:445285296882\   ┼-❷
          layer:perl-5-36-paws-al2-x86_64:1"
          
      FunctionUrlConfig:
        AuthType: NONE
      
      # 書き込み先のテーブル名を、
      # 環境変数経由でプログラムに渡す                       |
      Environment:                                   ├-❸
        Variables:                                   |
          TABLE_NAME: !Ref Table                     ┘
          
      # テーブルへの読み書き権限を付与
      Policies:                                      ├-❹
        - DynamoDBCrudPolicy:                        |
            TableName: !Ref Table                    ┘

❶でカウンタの数値を書き込むためのDynamoDBのテーブルを作成します。作成したテーブルの名前を❸でPerlのプログラムに渡します。❹はテーブルの読み書きの権限をLambda関数に付与するための設定です。

DynamoDBの読み書きを行うにはAWS SDKSoftware Development Kitが必要です。Perl 向けのSDKは公式には提供されていませんが、Pawsという有志による実装があります。❷はPawsモジュールを読み込む設定です。

テーブルへの書き込み処理の実装

DynamoDBにカウンタの値を書き込むプログラムを実装します。カウンタの値の更新にはDynamoDBのAPIであるUpdateItemを利用します。APIの詳細は、DynamoDBのデベロッパーガイドを参照してください。

リスト handler.pl
use v5.36;
use utf8;
use AWS::Lambda::PSGI;
use Paws;

# DynamoDBに接続するためのクライアントを作成
my $db = Paws->service(
    'DynamoDB',
    region => $ENV{AWS_DEFAULT_REGION}
);

my $app = sub {
    # カウンタをインクリメント
    my $ret = $db->UpdateItem(
        # DynamoDBのテーブル名
        TableName => $ENV{TABLE_NAME},
        
        # プライマリキーの指定
        Key => { id => { S => "data" } },
        
        # インクリメント命令を実行
        # :incrの部分はプレースホルダー
        UpdateExpression => 'ADD cnt :incr',
        
        # プレースホルダ :incrに1を設定
        ExpressionAttributeValues => {
            ':incr' => { N => '1' }
        },
        
        # 戻り値に更新後の値を返すよう設定
        ReturnValues => 'UPDATED_NEW',
    );
    
    # 結果を返す
    my $cnt = $ret->Attributes->Map->{cnt}->N;
    return [
        200,
        ['Content-Type' => 'text/plain'],
        ["$cnt\n"]
    ];
};

my $func = AWS::Lambda::PSGI->wrap($app);
sub handle ($payload, $context) {
    return $func->($payload);
}
1;

APIの動作確認

sam deployを使ってデプロイしましょう。APIを呼び出すたびに数値が増えていくことが確認できます。

$ sam deploy
$ curl https://xxxxx.lambda-url.ap-northeast-1.on.aws/
1
$ curl https://xxxxx.lambda-url.ap-northeast-1.on.aws/
2

まとめ

AWS Lambda入門ということで、Perlを使ってアクセスカウンタを作ってみました。本稿では一例としてHTTP APIを取り上げましたが、AWS Lambdaの利用はHTTP APIだけではありません。興味を持った人はぜひいろいろと試してみてください。

さて、次回の執筆者は岡林大さんで、テーマはコーディングを楽にするPerl Navigatorです。お楽しみに。

おすすめ記事

記事・ニュース一覧