2013-11-04 20 views
13

W jaki sposób można najlepiej wstrzykiwać stan do procedur obsługi pierścieni (bez użycia globalnych zmiennych)?Przekazywanie stanu jako parametru do obsługi pierścienia?

Oto przykład:

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

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

Chciałbym dostać the-state do obsługi compojure dla main-routes. Stan może być coś jak mapa utworzonej z:

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

W braku zastosowania pierścienia Chciałbym stworzyć państwo w głównej funkcji i rozpocząć wstrzykiwanie go, lub jego części, jako parametry funkcji do poszczególnych składników Aplikacja.

Czy można coś podobnego zrobić z funkcją pierścienia :init bez używania globalnego var?

+0

Szukasz stanu na sesję lub stanu globalnego? – astine

+0

globalne - samo życie jak: init i: destroy – 4ZM

Odpowiedz

20

Widziałem to na kilka sposobów. Pierwszy używa oprogramowania pośredniego, które wstrzykuje stan jako nowy klucz na mapie żądania. Na przykład:

(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)) 

Innym rozwiązaniem jest zastąpienie wywołanie defroutes, która za kulisami będzie utworzyć uchwyt i przypisać go do var, z funkcji, która przyjmie jakiś stan, a następnie tworzenie tras, wstrzykiwanie stan jako parametry do funkcjonowania połączeń wewnątrz definicji trasy:

(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)) 

Biorąc pod uwagę wybór, pewnie bym go z drugim podejściu.

+1

Dzięki! Drugie podejście wydaje się być dobrym rozwiązaniem. Ten pierwszy wydaje się nieco hack-owski. – 4ZM

-1

"Prawidłowy" sposób, aby to zrobić, to użycie dynamicznie związanego var. Zdefiniować var ​​z:

(def ^:dynamic some-state nil) 

A potem stworzyć jakiś middleware pierścień, który wiąże się z var dla każdego wywołania Handler:

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

byłoby użyć tego wstrzykiwać zależności używając tego w swoim „głównym "funkcja w momencie uruchomienia serwera:

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

Zamierzasz wejść w wiele zarządzania państwem za pomocą dynamiki. Może to spowodować później poważne problemy. – Virmundi

Powiązane problemy