Как я могу перехватить запрос Compojure и выполнить его на основе теста?

У меня есть несколько маршрутов.

(defroutes some-routes
    (GET "one" [] one)
    (GET "two" [] two))

(defroutes other-routes
  (GET "three" [] three)
  (GET "four" [] four))

(defroutes more-routes
  (GET "five" [] five)
  (GET "six" [] six))


(def all-routes 
  (routes app-routes
          (-> some-routes session/wrap-session my-interceptor)
          (-> more-routes session/wrap-session my-other-interceptor)
          other-routes))

Я хочу перехватить some-routes, но не other-routes, и выполнить тест на основе запроса (проверка наличия ключа в сеансе и некоторые другие вещи). У меня больше одного из них. my-other-interceptor делает то же самое, но по-другому.

Итак, я начинаю с этого:

(defn my-interceptor [handler]
    (fn [request]
      (prn (-> request :session :thing-key))
        (let [thing (-> request :session :thing-key-id)]
          (if (nil? thing)
            (-> (response "Not authenticated"))
            (handler request)))))

Это позволит получить доступ к обработчику, если в сеансе установлено :thing-key.

К сожалению, это не очень хорошо работает с более чем одним набором маршрутов. Эта проверка должна применяться только к some-routes, а не к other-routes. Но пока мы не выполним обработчик, мы не знаем, совпадает ли маршрут. И в этот момент обработчик уже выполнился. Я мог бы переписать его для выполнения handler, а затем выполнить проверку только в том случае, если ответ не равен нулю, но это означает, что я выполнил обработчик перед проверкой аутентификации.

Я следовал этому примеру, который демонстрирует проблему:

(defn add-app-version-header [handler]
  (fn [request]
    (let [resp (handler request)
      headers (:headers resp)]
      (assoc resp :headers 
        (assoc headers "X-APP-INFO" "MyTerifficApp Version 0.0.1-Alpha")))))

Как мне это сделать? Я хочу:

  • способ проверки ответа (и некоторой другой логики) перед обработкой запроса
  • которые я могу применить к большому набору обработчиков маршрутов
  • применяется не ко всем маршрутам в приложении
  • У меня будет более одного такого обработчика, выполняющего различные проверки сеанса.

Как мне это сделать?


person Joe    schedule 05.03.2014    source источник


Ответы (1)


Способ иметь отдельные обработчики или промежуточное ПО состоит в том, чтобы разложить ваши маршруты с помощью compojure.core/routes и использовать ваш обработчик только там, где он вам нужен.

В вашем случае, если вы сначала поставите other-routes, ваша проблема должна быть решена.

As in:

(def app-routes
   (compojure.core/routes
       other-routes
       (-> some-routes
           session/wrap-session
           my-interceptor)))

Помните, что маршруты compojure являются просто обработчиками колец. всегда можно написать собственный defroutes, который вызывает ваш обработчик, только если маршрут соответствует запросу, это создать исходный код маршрута

(defn make-route
  "Returns a function that will only call the handler if the method and Clout
   route match the request."
  [method route handler]
  (if-method method
    (if-route route
      (fn [request]
        (render (handler request) request)))))

Таким образом, если у вас есть более одного условного обработчика, вам не нужно полагаться на размещение этих маршрутов в конце композиции.

Обратите внимание, что этот подход нужен на тот случай, если вы хотите, чтобы ваш код обработки маршрутов был чистым.

(my-def-routes routes
    (GET "/" request (show-all request))

Если вы не хотите сворачивать свой собственный defroutes, просто вызовите свой перехватчик внутри:

(defroutes routes
   (GET "/" request (interceptor request show-all))

(defn interceptor
  [request handler]
person guilespi    schedule 05.03.2014
comment
Спасибо. Однако у меня есть несколько видов проверок, поэтому я думаю, что ваше предложение ставить сначала непроверенные элементы не применимо? Я рассмотрю ваше второе предложение. - person Joe; 05.03.2014
comment
Честно говоря, я новичок в Ring (и совсем новичок в Clojure). Мне придется отказаться от моего defroutes и переписать маршрут, чтобы сделать это? Также некоторые функции, например. if-route были def- изданы. Означает ли это копирование фрагментов кода из compojure или я упустил суть? - person Joe; 05.03.2014
comment
Что ж, вы всегда можете вызвать обработчик в своем обработчике маршрута, а не снаружи, ответ будет обновлен, чтобы показать. - person guilespi; 05.03.2014
comment
Спасибо, последний бит решает мою проблему на данный момент, и этого достаточно, чтобы что-то заработало, пока я изучаю остальную часть compojure и ring. - person Joe; 05.03.2014