diff --git a/modules/reitit-middleware/.nrepl-port b/modules/reitit-middleware/.nrepl-port new file mode 100644 index 00000000..d0d8aacb --- /dev/null +++ b/modules/reitit-middleware/.nrepl-port @@ -0,0 +1 @@ +43803 \ No newline at end of file diff --git a/modules/reitit-middleware/src/reitit/ring/middleware/session.clj b/modules/reitit-middleware/src/reitit/ring/middleware/session.clj index e90963e1..e0300204 100644 --- a/modules/reitit-middleware/src/reitit/ring/middleware/session.clj +++ b/modules/reitit-middleware/src/reitit/ring/middleware/session.clj @@ -2,15 +2,21 @@ (:require [clojure.spec.alpha :as s] [ring.middleware.session :as session] + [ring.middleware.session.store :as session-store] [ring.middleware.session.memory :as memory])) +(s/def ::store #(satisfies? session-store/SessionStore %)) +(s/def ::root string?) +(s/def ::cookie-name string?) +(s/def ::cookie-attrs map?) +(s/def ::session (s/keys :opt-un [::store ::root ::cookie-name ::cookie-attrs])) (s/def ::spec (s/keys :opt-un [::session])) (def ^:private store "The default shared in-memory session store. - This is used when no `:session` key is provided to the middleware." - (atom {})) + This is used when no `:store` key is provided to the middleware." + (memory/memory-store (atom {}))) (def session-middleware "Middleware for session. @@ -25,9 +31,9 @@ | key | description | | -------------|-------------| - | `:session` | `ring.middleware.session.store/SessionStore` instance. Use `ring.middleware.session.memory/MemoryStore` by default." + | `:session` | A map of options that passes into the [`ring.middleware.session/wrap-session](http://ring-clojure.github.io/ring/ring.middleware.session.html#var-wrap-session) function`." {:name :session :spec ::spec - :compile (fn [{:keys [session] - :or {session {:store (memory/memory-store store)}}} _] - {:wrap #(session/wrap-session % session)})}) + :compile (fn [{session-opts :session} _] + (let [session-opts (merge {:store store} session-opts)] + {:wrap #(session/wrap-session % session-opts)}))}) diff --git a/test/clj/reitit/ring/middleware/session_test.clj b/test/clj/reitit/ring/middleware/session_test.clj index ca4acfe7..efaf41f7 100644 --- a/test/clj/reitit/ring/middleware/session_test.clj +++ b/test/clj/reitit/ring/middleware/session_test.clj @@ -2,7 +2,9 @@ (:require [clojure.test :refer [deftest testing is]] [reitit.ring.middleware.session :as session] [ring.middleware.session.memory :as memory] - [reitit.ring :as ring])) + [reitit.spec :as rs] + [reitit.ring :as ring] + [reitit.ring.spec :as rrs])) (defn get-session-id "Parse the session-id out of response headers." @@ -24,37 +26,54 @@ :session {:counter counter}})) (deftest session-test - (let [store (atom {}) - app (ring/ring-handler - (ring/router - ["/api" - {:session {:store (memory/memory-store store)} - :middleware [session/session-middleware]} - ["/ping" handler] - ["/pong" handler]])) - first-response (app {:request-method :get - :uri "/api/ping"}) - session-id (get-session-id first-response) - second-response (app {:request-method :get - :uri "/api/pong" - :cookies {"ring-session" {:value session-id}}})] - (is (= (count @store) - 1)) - (is (-> @store first second) - {:counter 2}))) + (testing "Custom session store" + (let [store (atom {}) + app (ring/ring-handler + (ring/router + ["/api" + {:session {:store (memory/memory-store store)} + :middleware [session/session-middleware]} + ["/ping" handler] + ["/pong" handler]])) + first-response (app {:request-method :get + :uri "/api/ping"}) + session-id (get-session-id first-response) + second-response (app {:request-method :get + :uri "/api/pong" + :cookies {"ring-session" {:value session-id}}})] + (testing "shared across routes" + (is (= (count @store) + 1)) + (is (-> @store first second) + {:counter 2}))))) (deftest default-session-test - (let [app (ring/ring-handler - (ring/router - ["/api" - {:middleware [session/session-middleware]} - ["/ping" handler] - ["/pong" handler]])) - first-response (app {:request-method :get - :uri "/api/ping"}) - session-id (get-session-id first-response) - second-response (app {:request-method :get - :uri "/api/pong" - :cookies {"ring-session" {:value session-id}}})] - (is (= (inc (get-in first-response [:body :counter])) - (get-in second-response [:body :counter]))))) + (testing "Default session store" + (let [app (ring/ring-handler + (ring/router + ["/api" + {:middleware [session/session-middleware]} + ["/ping" handler] + ["/pong" handler]])) + first-response (app {:request-method :get + :uri "/api/ping"}) + session-id (get-session-id first-response) + second-response (app {:request-method :get + :uri "/api/pong" + :cookies {"ring-session" {:value session-id}}})] + (testing "shared across routes" + (is (= (inc (get-in first-response [:body :counter])) + (get-in second-response [:body :counter]))))))) + +(deftest session-spec-test + (testing "Session spec" + (testing "with invalid session store type" + (is + (thrown? Exception + (ring/ring-handler + (ring/router + ["/api" + {:session {:store nil} + :middleware [session/session-middleware] + :handler handler}] + {:validate rrs/validate})))))))