Подтвердить что ты не робот

Передача состояния в качестве параметра в обработчик кольца?

Как удобно вводить состояние в обработчики меток (без использования глобальных варов)?

Вот пример:

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

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

Я хотел бы получить the-state в обработчик compojure для main-routes. Состояние может быть чем-то вроде карты, созданной с помощью:

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

В нелокальном приложении я создам состояние в основной функции и начну вводить его или его части в качестве функциональных параметров для разных компонентов приложения.

Можно ли что-то подобное сделать с помощью функции ring :init без использования глобального var?

4b9b3361

Ответ 1

Я видел, как это делалось несколькими способами. Первый использует промежуточное программное обеспечение, которое вводит состояние в качестве нового ключа в карте запроса. Например:

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

Другой подход заключается в замене вызова на defroutes, который за кулисами создаст обработчик и назначит его var, с функцией, которая примет какое-то состояние, а затем создаст маршруты, введя состояние в качестве параметров для вызова функций в определениях маршрутов:

(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

"Правильный" способ сделать это - использовать динамически связанный 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 ...})))