シャッフル主任の進捗報告

興味のあるものを作ります。進捗を不定期にご報告します。

そうだ、教祖になろう。出エジプト記 第2章1節 LambdaとAPI Gatewayで動的コンテンツを生成する

To be or not to be


次に何をするか迷っています。
選択肢は以下です。

  1. サイトの公開を優先する
    →Route53で独自ドメインの取得へ進む

  2. サーバサイド処理の構築を優先する
    →LambdaやAPI Gatewayの設定へ進む

  3. 構築環境を整える
    →CodeCommitやCloud9の設定へ進む

創世記 第3章1節では偉そうにアジャイルやりますと言ってしまいましたが、実はアジャイル開発の経験はほとんどないので、はじめに目指すべき方向をどう決めればいいのかよくわかりません。

とにかく公開を優先するか、
裏側まで一応作り込んでから公開するか、
いやいや、変更や運用をしやすい環境を整える方があとあと効率いい気もします。

参考になるサイトがありました。

www.ryuzee.com

すべての要求の実装が短期間内に終わるような場合は要求はあまり注意深く優先順位付けしない(しても仕方ない)。

んーなるほど。
あんまり悩んでも仕方ないかもしれません。

1.は後回しにしましょう。
コンテンツはまだ"Hello, World"なので公開しても仕方ないですからね。

3.も後回し。
とりあえず、手作業ベースでひと通りのサービスを覚えて、必要になったところで環境・運用系のサービスを使っていきましょう。
その方がブログをご覧のみなさんにもわかりやすいかもしれません。

ということで、2.のサーバサイド処理を構築していくことにします。
こういう構成です。

f:id:chief-shuffle:20191124134247p:plain

この時点ではJavaScriptを使わずブラウザから直接アクセスします。

サーバレスなのにサーバサイドとはこれいかに


まず、Lambdaです。
Lambdaはサーバレスで処理を実行できるサービスです。

起動タイミングは時間起動、Webリクエスト起動のほか、他サービスから呼び出されて起動することもできます。
今回はWebリクエストをトリガとして起動してみます。
プログラミング言語は、JavaPowerShell、Node.jsなど7種類をサポートしています。
今回はLambdaでは割とポピュラーで前に書いたことがあるPythonを使います。

こちらの記事を参考にさせていただきました。

qiita.com

AWSに入ってリージョンを選択します。
Webサイトの訪問者はほぼ日本人と思われるので、「アジアパシフィック(日本)」を選択します。
これ結構忘れがちです。 最初、バージニア北部に作っちゃって全部やり直しました。

f:id:chief-shuffle:20191124145553p:plain

「サービス」でLambdaを選択します。

f:id:chief-shuffle:20191124150142j:plain

関数の一覧が表示されます。まだ何もありません。

f:id:chief-shuffle:20191124145807p:plain

「関数の作成」をクリック。
「一から作成」を選択。

f:id:chief-shuffle:20191124150359p:plain

「関数名」を入力。「ランタイム」はPythonの最新を選択します。

f:id:chief-shuffle:20191124150502p:plain

「実行ロールの選択または作成」を開きます。
AWSではこのロールという概念が大事で各所で出てきます。
簡単に言うと、サービスからサービスを起動する場合、起動する側が持っているべき起動される側へのアクセス権限です。
今回の場合は、API GatewayからこのLambda関数を起動できる権限のことですね。

f:id:chief-shuffle:20191124150936p:plain

ロールは私のような慣れてない人にとっては割と罠で、1回やり直したりすると作成されたロールは削除されないので、同名のロールが存在しますと怒られます。 その場合は「既存のロールを使用する」を選択したり、 IAMのページでロールを削除したりしてください。

さて、「関数の作成」をクリックすると以下の画面に移ります。

f:id:chief-shuffle:20191124151308p:plain

ちょっとわかりづらいかもしれませんが、真ん中にある「λ(ラムダ)」というオレンジ色のアイコンがこの関数を表しています。 左側がこの関数を起動しうるサービス群の定義ですが、まだ何もありません。
これからAPI Gatewayを足していきます。
右側はこの関数から連携されうるサービス群です。「Cloudwatch Logs」が表示されていますが、実際に連携が定義されているわけではありません。

「+トリガーを追加」をクリック。
「トリガーを選択」でAPI Gatewayを選択します。

f:id:chief-shuffle:20191124151918j:plain

API」で「新規APIの作成」、「セキュリティ」で「オープン」を選択。
「追加の設定」にはSPAで利用するCORS(オリジン間リソース共有)を設定できますが、今回は設定しません。
「追加」をクリック。

f:id:chief-shuffle:20191124151820p:plain

API Gateway」がトリガに追加されました。

f:id:chief-shuffle:20191124152421p:plain

関数の処理を実装します。 真ん中の「λ」アイコンをクリックします。

f:id:chief-shuffle:20191124152528p:plain

画面下の「関数コード」にプログラムコードが出てきます。

f:id:chief-shuffle:20191124152646p:plain

すでにWebの正常レスポンスを返す実装がされていますね。
'statusCode'(レスポンスコード)として200(正常)を、'body'(レスポンスボディ)で'Hello from Lambda!'を返しています。
こりゃ親切。
特に何もいじりません。

まず、API Gatewayと連動させず、Lambda単体の挙動を確認してみましょう。
画面右上の「テスト」ボタンをクリック。

f:id:chief-shuffle:20191124153353j:plain

「テストイベントの設定」が表示されます。
Webリクエストをシミュレートするため、
「新しいテストイベントの作成」を選択、「イベントテンプレート」で「Amazon API Gateway AWS Proxy」を選択。
イベント名を何かしらつけます。

f:id:chief-shuffle:20191124153704p:plain

作成したイベント名を選択してもう一度「テスト」をクリック。

f:id:chief-shuffle:20191124153829j:plain

実行結果が表示されます。「詳細」を開くと関数コードのreturnで指定した値がJSON形式に変換されて表示されているのが分かるでしょうか。

f:id:chief-shuffle:20191124153906p:plain

{
  "statusCode": 200,
  "body": "\"Hello from Lambda!\""
}

明るい蟻でもクライアント(暗いAnt)と言うが如し


それでは、このLambda関数をAPI Gateway経由で起動するよう設定を追加していきます。
画面の「API Gateway」をクリック。

f:id:chief-shuffle:20191124152421p:plain

その下に表示されるAPI名をクリック。

f:id:chief-shuffle:20191124205005p:plain

API Gatewayの設定画面に移ります。
「/」の下にLambda関数名と同じリソース名が表示されています。
クライアントからLambdaへのリクエスト送信(→方向)とそのレスポンス(←方向)が表現されています。

f:id:chief-shuffle:20191124205510p:plain

では、API Gateway経由のLambda起動をテストします。
クライアントの箱の中の「テスト」をクリック。

f:id:chief-shuffle:20191124154818p:plain

「メソッド」に「GET」を選択して「テスト」をクリックすると、その右側に結果が表示されます。
「ステータス: 200」で正常レスポンスが返りますね。

f:id:chief-shuffle:20191124205846p:plain

実はこれまでの手順でこのAPIはデプロイされて、インターネット経由でアクセスできるようになっています。
確認してみましょう。
画面左部から「ステージ」を選択し、「default」というステージ名をクリック。

f:id:chief-shuffle:20191130143826j:plain

画面中央部の「URLの呼び出し」のURLをそのままクリックするとパス違いでエラーが返されるのですが、

f:id:chief-shuffle:20191130144302j:plain

アドレスバーでURLの最後に先ほど作ったリソース名をつけると、

f:id:chief-shuffle:20191130144549j:plain

おお、Lambdaのreturn値が表示されました。

うまい!小遊三さんに座布団一枚で冬キャンプの刑!


これでやっと動的コンテンツを生成することができまし……

…ん?これ、動的である必要性が伝わりづらいね。
固定文字列返してるだけだもんね。
見てる人はS3でいいじゃんてなるね。

ということで、蛇足ですがさきほどのLambda処理をちょっと変えてみます。
現在時刻をレスポンスボディに足してみました。

f:id:chief-shuffle:20191124185633p:plain

import datetime
import json

def lambda_handler(event, context):
    # TODO implement
    return {
        'statusCode': 200,
        'body': json.dumps('Hello from Lambda! at ' + str(datetime.datetime.now()))
    }

これをさきほどのAPI Gatewayのエンドポイントで表示すると、

f:id:chief-shuffle:20191130144312j:plain

これで誰がどう見ても『動的に生成されるコンテンツ』です。
※あとでキャプチャを貼りなおしたでの時刻が変になっていますが、気にしないでください。

今回はやり直しもあり、思わぬ長丁場でした。
カフェで4時間も粘ってしまったため、回復傾向だった体調がまた悪化するかもしれません。
みなさんの読みやすさのためにも今後は少しずつ刻んでいった方がいいかもしれませんね。

次はAPI GatewayとCloudFrontをつなげたいと思います。