📝Clojure Web Development

📝Clojure Web Development

ClojureによるWeb開発ノウハウまとめ.

tags: 🏷Clojure 🏷Web Development

テーマが大きいので分割するかも.

Clojure Web Development概論 #

ClojureではRailsやDjangoのようなデファクトスタンダードなWebフレームワークをつかうよりも 小さなライブラリを組み合わせて開発することが多い.

そのため機能ごとにいろんなライブラリが存在する.

Clojure: Web Frameworks #

  • Luminus
  • Duct (正確には状態管理ライブラリ + モジュール作成テンプレート).

ref: 🏷Web Framework

Clojure: Ring #

Clojureにおける Web サーバ抽象 のデファクトスタンダード.

  • Why Use Ring? · ring-clojure/ring Wiki · GitHub
    • なぜRingをつかうのか?
      • WebアプリをClojureの関数とMapデータのみで構築するという設計概念を示す.
      • Java servletの上で走るアプリにコンパイルする.
  • 4つのコンポーネントからなる(ref).
    • Handler
      • Clojureの関数で表現される.
      • Request Mapを受取り, Response Mapを返す.
    • Request
    • Response
    • Middleware

ref: 🏷Web Server Abstruction 📝Clojure: Pedestal

ring: middleware #

ref. ring

  • wrap-params(ring.middleware.params)
    • ringはデフォルトではrequestに付随するパラメータに対してなにもしない. wrap-paramsを利用すると パラメータを処理してくれる.
    • (通常getからの) urlについたquery-paramsを :query-paramsにbind.
    • (通常postからの) bodyの中のform-paramsを :form-paramsにbind.
    • :query-paramsと :form-paramsのデータを :paramsにマージ. そのため大抵は :paramsをチェックすればデータが入っている.
  • wrap-keyword-params(ring.middleware.keyword-params)
    • ring は request-mapのkeyをdefaultではstringとして扱う.これをkeywordに変換する.
    • wrap-json-paramsの:json-paramsは ring parameter mapである :paramsにマージされる. しかしring paramsは mapのkeyがkeywordではなくstringとして扱うため wrap-keyword-params との併用が必要.

ring-json: middleware #

ref. ring-json (ring.middleware.json)

  • wrap-json-response
    • response-mapのbodyのColojure MapやVectorをplain/textのJSONに変換.
  • wrap-json-body
    • request-mapのbodyのjson形式の文字列をclojure collectionに変換して :bodyにbinding.
  • wrap-json-params
    • request-mapの bodyの json形式の文字列を Mapに変換して(:body :json-paramsにbinding.

tips: run-jettyにhandlerのvarを渡してhot reloading #

varは リーダマクロ #' にて取得できる. すなわち,

(run-jetty #'handler {:port 3000})

詳しくは以下を参照.

varというのが参照型のため実際を差し替えられる.

References #

Active Recalls #

Clojure RingのようなWebアプリを構築するための仕組みを一般的になんといいますか? #

Webサーバ抽象, Web Server Abstruction.

Web Serverと Web アプリがやり取りをするための仕様.

Clojure Ring における4つのコンポーネントはなんですか? #

ハンドラー, ミドルウェア, リクエストマップ, レスポンスマップ.

Heroku with Clojure #

leiningenの作者がHerokuで働いてたらしくドキュメントがていねいとか.

https://twitter.com/as_chapa/status/1198104444711256064 https://twitter.com/iku000888/status/1099293410693808128

tip: Heroku上のappにreplで接続 #

heroku run lein replでHerokuサーバ上でreplを起動できる.

heroku run lein repl

howto: Heroku Deployでlein deps失敗の対処方法 #

Leiningen 1.7.1 がデフォルトで使用されますが、project.clj に :min-lein-version “2.0.0"​ がある場合は (強く推奨されます)、Leiningen 2.9.1 リリースが代わりに使用されます。

これにハマった. project.cljに :min-lein-version “2.0.0” を記載して解決✨

ref: https://devcenter.heroku.com/ja/articles/clojure-support

howto: Heroku上で Botを動かそうとするとエラー #

web appではなく worker appにする必要がある.

そうしないと 60secでBootTimeoutとして扱われてProcess Killされる.

2022-02-11T09:30:12.486217+00:00 heroku[web.1]: Error R10 (Boot timeout) -> Web process failed to bind to $PORT within 60 seconds of launch
2022-02-11T09:30:12.581863+00:00 heroku[web.1]: Stopping process with SIGKILL
2022-02-11T09:30:12.834345+00:00 heroku[web.1]: Process exited with status 137
2022-02-11T09:30:13.225734+00:00 heroku[web.1]: State changed from starting to crashed

Procfileを新規作成して以下を記載.

worker: lein run

heroku cliより

heroku ps:scale worker=1

ただし workerは30分活動がないとsleepしてしまう.

実際はheroku schedulerの活用も検討.

howto: tools.deps管理のプロジェクトをHerokuにデプロイ #

未実施だけどブックマーク. leiningenの作者はライバルにいじわる?

ref: 試行錯誤な日々: clojure cliプロジェクトをherokuで動かす

Firebase/Google Cloud w/ Clojure #

🏷Firebase

ref: https://github.com/tsu-nera/meigen-bot-firebase-clj

Firebase Firestore(aka. Google Cloud Firestore) w/ Clojure #

せっかくのClojureなのでClojure onlyで頑張らずにJavaやnode.jsの資産を活用する方向がいいかな…Java資産活用しないとリッチーヒッキーの開発モチベに反する🤔

ref: 📝Firebase Firestore

client libraries #

firestore-cljがよくできている. これをベースに他のリポジトリを参考にカスタマイズするとよい.

💡Firestoreのスキーマレスのメリットとclojure.specの思想が反する #

FirestoreはスキーマレスDBということを留意する.

すなわちこの特性によりスキーマ設計が不要というメリットを活かすならば動的言語であるClojureとの 相性がよく JSON Schema(Shcema/Malli/clojure.spce)は不要かもしれない.

ref. 📝Clojure spec

💡FirestoreのドキュメントデータベースパラダイムとClojureプロトコルの思想が反する #

またFirestoreは ドキュメントデータベースということも注意.

ドキュメントのモデルを作成してプロトコルを定義する必要はあるのか?

なぜならばドキュメントはコレクションに格納されてその範囲内でのみシーケンス処理される.

プロトコルとは操作抽象であり異なるデータ型を同一IFでシーケンシャルに処理することが目的であるがそもそもドキュメントデータベースのパラダイムにおいては異なるドキュメントを同一コレクションに入れるのかという問題がある.

ref: defprotocol

タイムスタンプの扱い #

調査中だがわかったところまで,

  • java.time.x でFirestoreにデータを送るとobjectとして格納される.
  • java.instantでFirestoreにデータを送るとobjectとして格納される.
  • java.data.utilでFirestoreにデータを送るとTimestampとして格納される.

なのでタイムスタンプ型として時刻を格納するときはjava.util.Dateで投げる.

Firebase Functions(aka. Google Cloud Functions) w/ Clojure #

tags: 🏷GCF

ClojureScriptを利用してJavaScript(Node.js)のライブラリを使うのがよい.

しかしClojureの道に挑戦してしまった…地雷だらけ.

基本方針としては, Google Cluud FunctionsのJava11ランタイムのページをみながら, functions-framework-java を利用する.

2022.01時点での注意点としては,

📝Google Cloud Run w/ Clojure #

🏷Jib を利用してコンテナビルドする.

実際に検証した感触ではCloud Functionsよりも圧倒的に楽.

refs:

最近, jibbit というclojureからjibを扱いやすしたツールも登場(2022/01).

tag: 🏷GCR

References #


Tags