I'm getting a baffling behavior when using Ring where POST requests all give "Invalid anti-forgery token" but only do this when I have the handler behind a function.
So,
(def app app-routes)
works fine.
Whereas
(defn app [args]
(app-routes args))
throws anti-forgery errors for POST requests.
Minimal code example. :
(defroutes app-routes
(GET "/login" request (fn [req]
(html5
[:body
[:div
[:form {:action "/login" :method "post"}
(anti-forgery-field)
[:input {:name "username"}]
[:input {:name "password"}]
[:button {:type "submit"} "submit"]]]])))
(POST "/login" request (fn [req] "Yay!")))
; WORKS A-OK like this
(def app (-> app-routes (wrap-routes site-defaults)))
In my project.clj
:plugins [[lein-ring "0.12.5"]]
:ring {:handler myapp.application/app
But again, if I change this to be a function:
(defroutes app-routes
(GET "/login" request (fn [req]
(html5
[:body
[:div
[:form {:action "/login" :method "post"}
(anti-forgery-field)
[:input {:name "username"}]
[:input {:name "password"}]
[:button {:type "submit"} "submit"]]]])))
(POST "/login" request (fn [req] "Yay!")))
; ALL POST REQUESTS FAIL
(defn app [args]
(let [handler (-> app-routes (wrap-routes site-defaults)))]
(handler args)))
the all post requests fail due to forgery tokens. All GET requests work fine.
Stranger still: I thought maybe it didn't like being re-initialized, so I stuffed it into an atom
to make it more singleton-like
(def handler (atom nil))
(defn app [args]
(swap! handler #(when (nil? %)
(-> app-routes
(wrap-defaults site-defaults))))
(@handler args))
Now GET and POST requests work as expected. Except now wrap-reload (not pictured above) throws exceptions!
I have no idea why it is behaving this way, and have been completely unable to debug. Could anyone shed some light?
Edit:
For context on why I'm trying to wrap it at all: I want to be able to wire up dependencies (like database connections) and then inject them into the controllers used by the routes .
(wrap-routes site-defaults)
rather than(wrap-defaults site-defaults)
. – clartaq