dependency-injection clojure compojure ring

dependency injection - ¿Pasar el estado como parámetro a un manejador de anillo?



dependency-injection clojure (2)

He visto esto hecho de varias maneras. El primero es usar middleware que inyecta el estado como una nueva clave en el mapa de solicitud. Por ejemplo:

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

El otro enfoque es reemplazar la llamada a defroutes , que detrás de las escenas creará un controlador y lo asignará a una var, con una función que aceptará algún estado y luego creará las rutas, inyectando el estado como parámetros para las llamadas de función dentro del definiciones de ruta:

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

Si tuviera una opción, probablemente iría con el segundo enfoque.

¿Cómo se puede inyectar el estado en controladores de anillo de la manera más conveniente (sin usar vars globales)?

Aquí hay un ejemplo:

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

Me gustaría obtener the-state en el controlador de compojure para main-routes . El estado podría ser algo así como un mapa creado con:

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

En una aplicación sin anillo, crearía el estado en una función principal y comenzaría a inyectarlo, o partes de él, como parámetros de función a los diferentes componentes de la aplicación.

¿Se puede hacer algo similar con ring''s :init function sin usar una var global?


La forma "correcta" de hacer esto es usar una var. Dinámicamente unida. Usted define una var con:

(def ^:dynamic some-state nil)

Y luego creas un middleware de anillo que vincula la var para cada llamada de controlador:

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

Usted usaría esto para inyectar dependencias al usar esto en su función ''principal'' donde ejecuta el servidor:

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