Passing state as parameter to a ring handler?

回眸只為那壹抹淺笑 提交于 2019-11-30 11:54:26

I've seen this done a couple of ways. The first is using middleware that injects the state as a new key in the request map. For instance:

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

The other approach is to replace the call to defroutes, which behind the scenes will create a handler and assign it to a var, with a function that will accept some state and then create the routes, injecting the state as parameters to function calls within the route definitions:

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

Given a choice, I'd probably go with the second approach.

The "correct" way to do this is to use a dynamically bound var. You define a var with:

(def ^:dynamic some-state nil)

And then you create some ring middleware which binds the var for each handler call:

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

You would use this to inject dependencies by using this in your 'main' function where you launch the server:

(def app (-> handler
             (wrap-some-state-middleware {:db ... :log ...})))
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!