Sessions in 0.4

7 views
Skip to first unread message

klancaster1957

unread,
Jun 1, 2010, 11:17:39 AM6/1/10
to Compojure
Ok - that was odd - this came up as a change of topic in another
thread. Not sure how that happened...

I'm just really getting started with Compojure, coming from a Rails
background, and am confused about how to handle sessions in 0.4. Can
someone give me the recommended way to handle them? Specifically, what
is the best way to set and retrieve values from the session? (Examples
would really help...)

Thanks,
Keith Lancaster
klancaster1...@acm.org

Brenton

unread,
Jun 1, 2010, 12:55:30 PM6/1/10
to Compojure
Keith,

Start by reading the doc for wrap-session a couple of times.

http://github.com/mmcgrana/ring/blob/master/ring-core/src/ring/middleware/session.clj

If the response map contains a :session key then that is the new value
of the session. If it contains a session key and the value is nil then
the session is deleted. If no session key is present then the session
is unaltered.

Here is one example of a complete tiny app.

http://github.com/brentonashworth/sandbar/blob/master/examples/src/example/session_demo.clj

The function named functional-handler shows one way to get and put
something in the session using Ring's built in support.

In order to make this work, you need to wrap your routes with wrap-
session. I am doing something a little different here but you can
replace wrap-stateful-session with wrap-session and the functional-
handler function will continue to work.

I created wrap-stateful-session because I like to treat the session as
if it were a global hash-map. The stateful-handler function shows how
to use it. wrap-stateful-session will dump the contents of the session
into an atom that you can then manipulate through get and put
functions. On the way out it will dump the contents of the atom into
the session.

I hope this is helpful.

Brenton

Keith Lancaster

unread,
Jun 1, 2010, 4:26:47 PM6/1/10
to comp...@googlegroups.com
Brenton,
Thanks - this helps a great deal. May need to read wrap-session a few more times... :-)

Keith

> --
> You received this message because you are subscribed to the Google Groups "Compojure" group.
> To post to this group, send email to comp...@googlegroups.com.
> To unsubscribe from this group, send email to compojure+...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/compojure?hl=en.
>

Keith Lancaster
klancas...@acm.org


James Reeves

unread,
Jun 1, 2010, 4:27:17 PM6/1/10
to comp...@googlegroups.com
On 1 June 2010 16:17, klancaster1957 <klancas...@gmail.com> wrote:
> I'm just really getting started with Compojure, coming from a Rails
> background, and am confused about how to handle sessions in 0.4. Can
> someone give me the recommended way to handle them? Specifically, what
> is the best way to set and retrieve values from the session? (Examples
> would really help...)

Compojure is a far lighter framework than Rails, and doesn't mandate a
particular library for handling sessions. Ring comes with session
handling middleware, but there are also alternative session handling
libraries like Sandbar.

I'll focus on Ring's session middleware. The session is encoded in the
request map under the :session key. Here's an example route that uses
the session:

(GET "/" {session :session}
(str "Hello " (session :user)))

To write to the session, you need to add the updated session to the
response map under the :session key. Here's an example route that sets
the session:

(GET "/set" {session :session, params :params}
{:session (assoc session :user (params :user))
:body "Session set"})

To wrap your routes in the session middleware, first load in the
appropriate namespace:

(use 'ring.middleware.session)

And then use wrap! to wrap your routes in the session middleware:

(wrap! app :session)

Putting it all together, you'll have something like:

(ns session-test
(:use compojure.core, ring.middleware.session, ring.adapter.jetty))

(defroutes app
(GET "/" {session :session}
(str "Hello " (session :user)))
(GET "/set" {session :session, params :params}
{:session (assoc session :user (params :user))
:body "Session set"})

(wrap! app :session)

(run-jetty app {:port 8080})

However, that's somewhat of a clunky way to use sessions. Usually,
you'll wrap your session handling in some manner of middleware. For
instance:

(declare *user*)

(defn wrap-user [handler]
(fn [{session :session :as request}]
(binding [*user* (session :user)]
(handler request))))

Then, if you wrap your app in wrap-user as well as wrap-session,
you'll get the *user* binding bound to a value in the session:

(defroutes app
(GET "/" []
(str "Hello " *user*))
(GET "/set" {session :session, params :params}
{:session (assoc session :user (params :user))
:body "Session set"})

(wrap! app :user :session)

(run-jetty app {:port 8080})

In many ways, the ring session handling middleware is less concise
than something you'd find in Rails, but it has the advantage of being
easily manipulated by middleware. Compojure emphasises a composition
of small components, rather than a monolithic design like Rails.

Although, if you want session handling that's a little easier to use
manually, the wrap-stateful-session middleware in Sandbar looks a nice
alternative.

- James

Daniel Werner

unread,
Jun 2, 2010, 2:24:28 PM6/2/10
to Compojure
Thank you for such a clear and helpful tutorial on sessions, James.
This would make an excellent addition to the documentation.

Daniel

Keith Lancaster

unread,
Jun 2, 2010, 2:32:01 PM6/2/10
to comp...@googlegroups.com
Yes - meant to respond yesterday on this. Your email James was quite helpful.

Reply all
Reply to author
Forward
0 new messages