朝活.Kotlinで作ったServerless Framework × Kotlin × LambdaのサーバーレスAPIまとめです。
概要
題材
上記のSlackBotのバックエンドをLambda関数で実装する.
CI/CDファーストを目標に、なるべくも手作業を減らしてビルド&デプロイを簡単にする.
- CloudFormationを組むのは個人的にはしんどい&気軽にできるものとは思っていないので、Serverless Frameworkを使ってデプロイを行います.
- 参考: 至高のCI/CDパイプラインを実現する5つの約束
やったこと
まずアプリケーションを作成するときに悩むのが、ボイラープレートコード(フレームワーク等で必要になる典型的なコード)の扱い。 ビジネスロジックを書くことに集中できるのがサーバーレスアプリケーションの強みの1つなので、LambdaとAPI Gatewayの接続部分や、エントリーポイントのHandlerクラスはなるべく書きたくないところ。
実はServerless Frameworkのテンプレートから雛形は自動生成可能です(プラットフォームによってはない)。
sls create --help
を打って調べる限り, 使えるテンプレートは3つありますね。KotlinでJS使うテンプレートなんてあるのか...
それでは雛形をコマンドラインから作成。事前にnpm i -g serverless
でserverlessコマンドは入れておきましょう。今回は"aws-kotlin-jvm-maven"を使います。
serverless create \ --template aws-kotlin-jvm-maven \ --path matsuya-finder \ --name matsuya-finder
5秒くらいでテンプレートは作成されます。指定した--path
以下は以下のようなディレクトリ構成になっています。
. |- pom.xml |- serverless.yml |- src |- main |- kotlin |- com |- serverless |- ApiGatewayResponse.kt |- Handler.kt |- Response.kt
ApiGatewayResponse.kt
... Lambda --> API Gatewayにレスポンスを返す時のデータの格納クラス。弄らずにそのまま使うHandler.kt
... アプリケーションのエントリーポイント。ビジネスロジックはここにInjectする。Response.kt
... アプリケーションのレスポンス。data classになっている。serverless.yml
... Serverless Frameworkに管理されたアプリケーションのデプロイ定義。裏ではCloudFormationを使っている。
あとは業務ロジックのコードを好きに書きます!
最終的なコードは以下の図のような構成になりました。 アプリのコードが重くなければ、KtorやJavaliなどのWeb Application Frameworkを使うよりもスッキリしてますね!
また、serverless.yml
は以下の構成になっています。このファイルが置かれている場所で sls deploy
を発行すればデプロイ完了です。
service: chom-matsuya-finder # Base Definition provider: name: aws runtime: java8 stage: dev region: ap-northeast-1 # Packaging information package: artifact: target/matsuya-finder-dev.jar # Individual Function Definitions functions: main: handler: net.ponzmild.Handler name: matsuya-finder description: Fetch today's Matsuya menu. events: - http: method: post path: matsuya
Tips
Serverless Frameworkのコマンドを打つときは, 権限のあるプロファイルを使おう
- IAMロールをつけたのになぜかUnauthorizedとなってしまうことありますが、だいたいはIAMロールをつけたユーザーでCLIを叩いてないことが原因です。
- (使用例)
sls deploy --aws-profile your-serverless-agent
そのままデプロイすると統合リクエストのタイプが"Lambda Proxy"になる
- このタイプはリクエストのコンテントタイプを細かく指定しづらいです。
- また、雛形として自動生成される
ApiGatewayResponse.kt
はLambda Proxyタイプ用のレスポンス定義です!これ以外のタイプは別途レスポンスのクラスを用意しましょう。 serverless.yml
でintegration:lambda
を指定するか、Handlerクラス内でパースのどちらかで解決しなければなりません。- 今回は後者にしています(以下のコード)
class Handler : RequestHandler<Map<String, Any>, ApiGatewayResponse> { override fun handleRequest(input: Map<String, Any>, context: Context): ApiGatewayResponse { // API GatewayのイベントのJSONからリクエストボディのみ取り出す val inputJsonString = input.get("body") as String // 全て文字列なので, Mapに詰め替える var inputBodyMap: HashMap<String, String> = hashMapOf() val kvStrings = inputJsonString.split("&") kvStrings.forEach { val kv = it.split("=") inputBodyMap.put(kv[0], kv[1]) // 詰め替え } // And more... } }
Kotlinも結構簡単にサーバーレスなAPIを作れるんですね。他にもS3のイベントやCloudWatch Eventsにも対応できるのでできる幅も広そう。 また、Androidユーザーはフロントエンドと同じ言語を使えるからいいですね。iOSユーザーのためにSwiftでもできるのかな?
以上。