Setting up a server for Lisp web apps
Table of Contents
Introduction
This note documents how to set up a basic Lisp web app server.
Software
The main software that Yu'll need is a Lisp interpreter. These instructions assume sbcl (Steel Bank Common Lisp) but other Lisp implementations may work as well. On Debian you can install sbcl using apt:
$ sudo apt-get install sbcl
To run the server on port 80, we'll use the program setcap
$ sudo apt-get install libcap2-bin
Libraries
The main Lisp libraries we will use are huchentoot and cl-who. These can be installed using a the quicklisp Lisp package manager. According to https://www.quicklisp.org/beta/ quicklisp may be installed as follows:
$ curl -O https://beta.quicklisp.org/quicklisp.lisp $ sbcl --load quicklisp.lisp * (quicklisp-quickstart:install) * (ql:add-to-init-file) * (quit)
This installs quicklisp. To install hunchentoot and cl-who, we can go back into sbcl and use quicklisp:
$ sbcl * (ql:quickload :hunchentoot) * (ql:quickload :cl-who) * (quit)
Now we are ready to run our first Lisp web app.
Example code
Here is the source code of hello.lisp:
(require "hunchentoot") (require "cl-who") (use-package :cl-who) (use-package :hunchentoot) (defclass search-server (acceptor) ((dispatch-table :initform '() :accessor dispatch-table :documentation "List of dispatch functions"))) (defvar *mysrv* (make-instance 'search-server :port 80)) (defun find-not-nil (l p) (if (endp l) nil (or (funcall p (car l)) (find-not-nil (cdr l) p)))) (defmethod acceptor-dispatch-request ((srv search-server) (req request)) (let ((l (find-not-nil (dispatch-table srv) (lambda (disp) (funcall disp req))))) (or l (call-next-method)))) (defmacro with-html ((var) &body body) `(with-html-output-to-string (,var) ,@body)) (defun my-prefix-disp (prefix handler) (lambda (req) (let ((m (mismatch prefix (script-name* req)))) (if (or (null m) (>= m (length prefix))) (funcall handler req))))) (defun push-dispatcher (srv disp) (push disp (dispatch-table srv))) (let ((counter 0)) (defun dummy-dispatch (req) (with-html (s) (:html (:body "Greetings! You are visitor number " (str (incf counter))))))) (push-dispatcher *mysrv* (my-prefix-disp "/hello" (quote dummy-dispatch))) (start *mysrv*)
Next we will see how to run our web app.
Launching the web app
First, we need to allow hunchentoot to listen on port 80. This can be done with the setcap program:
$ sudo setcap 'cap_net_bind_service=+ep' /usr/bin/sbcl
Start the web app as follows:
$ sbcl * (load "hello.lisp")
You may see a few warnings; these can be ignored.
Testing it out
Launch a web browser and visit http://yoursite/hello. If everything is working, you should see something like this
Something you can play with: Refresh the page a few times and note how the visitor number field is updated.
This logic is implemented inside the web app in the dummy-dispatch function (look for the call to incf there)