This post describes what I learnt about these two options. Though the code to implement this feature is minimal, it took me much too long to figure out the details necessary to do so.
Writing your own storage layer has the following advantages:
- You can use storage not supported by cl-dbi, i.e. MySQL, PostgreSQL and SQLite.
- You determine the table layout.
My suggestion is to use the included version. It will save you time. I only created my own version because I did not know Clack already included the necessary module.
Using Clack’s storage middleware
This information is correct at least up to commit c4f3e09 (2015-10-27)
The class name is
<clack-session-store-dbi> located at
The code below creates a Clack application which handles the storage of session information completely automatically.
(clack:clackup (builder (<clack-middleware-session> :store (make-instance 'clack.session.store.dbi:<clack-session-store-dbi> :connect-args '(:postgresql :database-name "DBNAME" :username "ROLE" :password "PASSWORD"))) #'app))
A hash table containing the session information is available inside request
handlers. It is obtained with
(getf env :clack.session).
The hash table content is serialized before being stored to disk so it can be used to store any arbitrary data.
Session tracking is done using cookies which contain only a session ID. All other session information are kept server side.
Writing your own persistence middleware
The code below implements middleware for a storage layer. The actual database access is done by the
(in-package :cl-user) (defpackage sltv.session.store (:use :cl :clack.session.store)) (in-package :sltv.session.store) (cl-syntax:use-syntax :annot) @export (defclass <sltv-session-store> (<clack-session-store>) ()) @export (defmethod fetch ((this <sltv-session-store>) sid) (let* ((session (model:fetch-session-as-hashtable sid))) (setf (gethash :id session) sid) session)) @export (defmethod store-session ((this <sltv-session-store>) sid session) (model:store-session sid session)) @export (defmethod remove-session ((this <sltv-session-store>) sid) (model:remove-session sid))
sidis the session ID generated by Clack.
- The session hash table must contain a key
IDwhich is set to the
sidnot the database record’s ID field.
sessionmust be defined with
(make-hash-table :test 'equal).
fetchobtains an existing session from the database or creates a new entry if it doesn’t exist.
store-sessionstores the session hash table and sid in the database.
remove-sessiondeletes the database record.
When an HTTP request is received the session middleware fetches the
session for the received
sid. If the request did not include an
sid (i.e. no cookie) or it included an expired
generates a new one and fetches (which should create an new record) the
The request handler has three option settings with which it can control some of the session middleware’s actions.
- Do not store the session object. It is still created in the database and available in the request handler but the database entry is deleted before the response is returned.
- Expire the session so that a new one is generated next time the user visits.
- Create a new session and populate it with the current data.
An option can be changed with the form
(setf (gethash :change-id (getf env :clack.session.options)) t)