2013-11-04 9 views
13

どのようにリングハンドラに状態を注入するのが最も便利です(グローバル変数を使わないで)?ここで状態をパラメータとしてリングハンドラに渡しますか?

は一例です:

(defroutes main-routes 
    (GET "/api/fu" [] (rest-of-the-app the-state))) 

(def app 
    (-> (handler/api main-routes))) 

私はmain-routesためcompojureハンドラにthe-stateを取得したいと思います。のさまざまなコンポーネントへの関数のパラメータとして、非リング私は主な機能の状態を作成し、それを注入開始するアプリケーション、またはその一部で

(defn create-app-state [] 
    {:db (connect-to-db) 
    :log (create-log)}) 

:状態はで作成したマップのようなものかもしれませんアプリケーション。

グローバルなvarを使用しないで、リングの:init機能で同様のことを行うことはできますか?

+0

セッションごとの状態またはグローバルな状態をお探しですか? – astine

+0

グローバル - :initと同じ寿命:破壊 – 4ZM

答えて

20

私はこれをいくつかのやり方でやってきました。最初は、リクエストマップに新しいキーとして状態を注入するミドルウェアを使用しています。例えば:

(defroutes main-routes 
    (GET "/api/fu" [:as request] 
    (rest-of-the-app (:app-state request)))) 

(defn app-middleware [f state] 
    (fn [request] 
    (f (assoc request :app-state state)))) 

(def app 
    (-> main-routes 
     (app-middleware (create-app-state)) 
     handler/api)) 

他のアプローチは、いくつかの状態を受け入れた後、ルートを作成する機能と、舞台裏でハンドラを作成し、VARに割り当てdefroutesへの呼び出しを、交換することです、ルート定義内の関数呼び出しにパラメータとして状態を注入する:

(defn app-routes [the-state] 
    (compojure.core/routes 
    (GET "/api/fu" [] (rest-of-the-app the-state)))) 

(def app 
    (-> (create-app-state) 
     app-routes 
     api/handler)) 

選択肢があるとすれば、私はおそらく2番目のアプローチに行きます。

+1

ありがとう! 2つめのアプローチは良いフィット感があるようです。最初の人はちょっとハックしています。 – 4ZM

-1

これを行う「正しい」方法は、動的にバインドされたvarを使用することです。あなたはとVARを定義します。

(def ^:dynamic some-state nil) 

そして、あなたは、各ハンドラ呼び出しのためのVARを結合し、いくつかのリングミドルウェアを作成します。

(defn wrap-some-state-middleware [handler some-state-value] 
    (fn [request] 
    (bind [some-state some-state-value] 
     (handler request)))) 

あなたはあなたの「メインでこれを使用して依存関係を注入するためにこれを使用します'機能を使用してサーバーを起動します。

(def app (-> handler 
      (wrap-some-state-middleware {:db ... :log ...}))) 
+0

あなたはダイナミックを使って多くの状態管理に入るつもりです。後で深刻な問題が発生する可能性があります。 – Virmundi

関連する問題