I am writing a web app that would require the hunchentoot web server. I have almost no working knowledge of hunchentoot, or any web server for that matter, and I am wondering how my app written in Common Lisp would serve pages to a web client. I have seen some excellent examples (e.g. Hunchentoot Primer, Lisp for the Web) esp. the one listed on the Hunchentoot page. Do you know where I can find more of such examples? Thanks.
2 Answers
I am wondering how my app written in Common Lisp would serve pages to a web client.
Hunchentoot serves all things that are in its *dispatch-table*, which is just a list of dispatch handlers.
The simplest thing to do is to serve a static file. One typical example would be a CSS file:
(push (create-static-file-dispatcher-and-handler "/example.css"
"example.css")
*dispatch-table*)
For a web application, you would most likely want to dynamically create a web page. You do this by defining a function that returns the page as a string (e.g. with CL-WHO), then creating a handler for this function:
(defun foo ()
(with-html-output-to-string ; ...
))
(push (create-prefix-dispatcher "/foo.html" 'foo)
*dispatch-table*)
You can eliminate a lot of boilerplate through macros, by the way:
(defmacro standard-page ((title) &body body)
`(with-html-output-to-string (*standard-output* nil :prologue t :indent t)
(:html :xmlns "http://www.w3.org/1999/xhtml"
:xml\:lang "de"
:lang "de"
(:head
(:meta :http-equiv "Content-Type"
:content "text/html;charset=utf-8")
(:title ,title)
(:link :type "text/css"
:rel "stylesheet"
:href "/example.css"))
(:body
,@body))))
(defmacro defpage (name (title) &body body)
`(progn
(defmethod ,name ()
(standard-page (,title)
,@body))
(push (create-prefix-dispatcher ,(format nil "/~(~a~).html" name) ',name)
*dispatch-table*)))
The examples you have found should be sufficient to get you started, and if you run into problems, read the manual, then ask concrete questions.
define-easy-handler registers the handler you are defining automatically in a global variable which gets checked when a HTTP request arrives (the variable is called *easy-handler-alist*). So it's being taken care of automatically. Do you want to use a handler of a different form than the one defined in the tutorial?
I think there is an example using Hunchentoot in the Elephant distribution (Elephant being a Persistent Object Database for Common Lisp.)