Coast has first-class session support with a variety of inbuilt drivers to efficiently manage and store sessions.
In this guide, we learn how to configure and use these different session drivers.
Below is the list of stores supported by Coast.
You can change the current store by adding one to your deps.edn
file and specifying it in the app
map.
Note: The redis and jdbc stores are not included with coast by default.
Name | Function | Description |
---|---|---|
Cookie | cookie-store | The default store used by coast, stores sessions in encrypted cookie |
Memory | memory-store | In-memory store, all sessions will be reset on server restart |
JDBC | jdbc-store | Stores the sessions in a database table |
Redis | redis-store | Stores the sessions in redis |
The session
object is passed as part of the request map
Here's a quick example of how to use sessions during the HTTP lifecycle:
(ns server
(:require [coast]))
(def app (coast/app {:session {:store (cookie-store {:key "16 byte secret key"})}}))
Then later on in a handler function:
(defn index [request]
(let [authenticated-person (get-in request [:session :person/id])]
(if (some? authenticated-person)
[:h1 "You're logged in!"]
[:a {:href (coast/url-for :login)} "Log in here"])))
Here's how to set a session after a person signs in or creates an account:
(defn create [request]
(-> (coast/redirect-to :after-sign-up)
(assoc :session {:person/id 123})))
If you don't feel like checking if someone is authenticated in every handler function, feel free to use middleware:
; src/middleware.clj
(defn auth [handler]
(fn [request]
(let [person (get-in request [:session :person/id])]
(if (some? person)
(handler request)
(coast/unauthorized "HAL9000: Sorry Dave, I can't let you do that")))))
Then you can wrap the routes that require auth:
; src/routes.clj
(def routes
(coast/site
[:get "/" :home/index]
[:get "/sign-in" :session/build]
[:post "/sessions" :sessions/create]
(coast/with middleware/auth
[:get "/dashboard" :home/dashboard]))))
Flash messages are short-lived session values for a single request only. They are mainly used for success messages, but can be used for any other purpose.
Let's say we want to validate submitted user data and redirect back to our form if there aren't any validation errors.
Start with the following HTML form:
; src/customer.clj
(defn build [request]
(coast/form-for ::create
[:input {:type "text" :name "customer/email"}]
[:button {:type "submit"} "Submit"]))
Then, add the /customers
routes to validate form data:
(def routes
(coast/site
[:get "/customers/build" :customer/build]
[:post "/customers" :customer/create]
[:get "/customers/:customer-id" :customer/view]))
...and implement the handler
; src/customer.clj
(defn create [request]
(let [[_ errors] (-> (select-keys (:params request) [:customer/email])
(coast/validate [[:email [:customer/email]]])
(coast/rescue))
(if (nil? errors)
(-> (redirect-to ::view)
(flash "Thanks for signing up!"))
(customer/build (merge request errors)))))
Finally, write the view handler to show the flash message:
; src/customer.clj
(defn view [request]
[:div
(when (some? (:flash request)))]
(:flash request))
Here's the whole customer.clj
file just for kicks and giggles:
; src/customer.clj
(defn build [request]
(coast/form-for ::create
[:input {:type "text" :name "customer/email"}]
[:button {:type "submit"} "Submit"]))
(defn create [request]
(let [[_ errors] (-> (select-keys (:params request) [:customer/email])
(coast/validate [[:email [:customer/email]]])
(coast/rescue))
(if (nil? errors)
(-> (redirect-to ::view)
(flash "Thanks for signing up!"))
(customer/build (merge request errors)))))
(defn view [request]
[:div
(when (some? (:flash request)))]
(:flash request))
Can you improve this documentation?Edit on GitHub
cljdoc is a website building & hosting documentation for Clojure/Script libraries
× close