AWS LambdaでClojureを使いたかった

はじめまして。analysisチームの河野です。ここ2年ぐらい趣味でLispを勉強しています。
最近はClojureでwebサーバみたいなものを作ったりして遊んでいます。

業務ではTypeScriptとAWS Lambdaでサーバレスなアプリケーションを作っていますが
AWS LambdaでもClojureを使いたい、Javaも使えるのだからClojureも使えるはずと思ったので、調べてみると、古い記事ですが、公式ブログで解説されていました。
https://aws.amazon.com/jp/blogs/compute/clojure/

ちょっと大変そう。。。

Nodeが実行できるのだから、ClojureScriptも使えるのでは?
調べてみると、Serverless Frameworkのプラグインがありました。
https://github.com/nervous-systems/serverless-cljs-plugin

ClojureScriptは使ったことはないのですが、とりあえずREADMEにしたがって進めてみます。

$ lein new serverless-cljs example
$ cd example
$ lein deps

依存関係の解決ができたらひとまずデプロイします。

$ serverless deploy

デプロイに成功したら、エンドポイントが表示されるの試してみます。 おそらく、echoというハンドラ名からして受け取った値をそのまま返すのだと思います。

$ curl -X POST -d '{"hello": "world"}' https://xxxx/dev/echo
-> {"hello": "world"}

bodyの値がそのまま返ってくる。jsonでなくても良いみたい。

$ curl -X POST -d "hello" https://xxxx/dev/echo
-> hello

ひとまずコードを見てみる。

(defgateway echo [event ctx]
  {:status  200
   :headers {:content-type (-> event :headers :content-type)}
   :body    (event :body)})

おそらく、defgatewayというのでハンドラを定義できるのでしょう。 中身はMapになっており、キーが、status, header, bodyなので、HTTPと対応しているように見えます。 よくわからないですが、bodyの値に何か別の値を入れれば、別の値を返せるっぽいので試してみます。

core.cljsにハンドラを追加します。

(defgateway hello [event ctx]
  {:status 200
   :headers {:content-type (-> event :headers :content-type)}
   :body "hello world"})

serverless.ymlにも設定を追加。 functionshelloを追加。

functions:
  echo:
    cljs: example.core/echo
    events:
      - http:
          path: echo
          method: post
  hello:
    cljs: example.core/hello
    events:
      - http:
          path: hello
          method: get

デプロイ。

$ serverless deploy

成功したらhelloのエンドポイントが表示されるので、ブラウザからアクセスしてみます。

f:id:t-kono0912:20190215162240p:plain
hello_wolrd

表示されてる。

せっかくなので、クエリストリングの値を返してみましょう。 こんな感じで送って

curl https://xxxx/dev/hello?name="your-name"

こんな感じで返したい。

{hello: "your-name"}

クエリストリングがなければ"world"と返す。

{hello: "world"}

helloハンドラを修正します。

(defgateway hello
  [event ctx]
  (let [name (get-in event [:query :name])]
    {:status 200
     :headers {:content-type "application/json"}
     :body (JSON/stringify (clj->js {:hello (or name "world")}))}))

serverless.ymlも修正。

  hello:
    cljs: example.core/hello
    events:
      - http:
          path: hello
          method: get
          request:
            parameters:
              querystrings:
                name: false

試してみる。

# パラメータなし
$ curl https://xxxx/dev/hello -v
-> {"hello": "world"}
# パラメータあり
$ curl https://xxxx/dev/hello?name="hoge" -v
-> {"hello": "hoge"}

できてる。 次回はパスパラメータを取れるようにしたいです。

コネクトムではエンジニアを募集しています。 https://open.talentio.com/1/c/connectom/requisitions/550