Common Lisp interface
We're getting down to details now. I'll document in this section how to interface with Common Lisp, that is, define your own primitive functions, define custom template handlers etc.
Sytes doesn't implement its own data structures; instead it uses ordinary Common Lisp values, which makes it easy to interface with CL. Even a lambda, compiles to an ordinary CL function, which means you can pass functions defined in Sytes to Common Lisp, i.e.:
{[defun list-item (text) { <li>{\text}</li> }]}
{(mapcar list-item '(1 2 3))}
|
→ |
<li>1</li> <li>2</li> <li>3</li>
|
[mapcar is the standard Common Lisp function, not implemented in Sytes].
Defining your own primitive functions
You might want to look in template/compiler.lisp and sytes.lisp from the Sytes source code to see many examples.
Primitives can be made globally available (to all Sytes running in the same Lisp image) or can be per-syte. Back to our first example from the Hello World page, it looked like this:
;; in file: /tmp/syte.foobar/syte.foobar.lisp
(defclass syte.foobar (syte)
()
(:default-initargs
:names '("www.foobar.com" "foobar.com" "foobar.local")
:root (merge-pathnames "root/"
(asdf:component-pathname
(asdf:find-system :syte.foobar)))))
;; create the Syte instance
(defparameter *site* (make-instance 'syte.foobar))
;; register it with Sytes
(register-syte *site*)
Now for example in order to define the primitive that we referenced in the dhandlers example we can do:
(sytes:def-syte-primitive *syte* "fetch-blog-entry"
(lambda (path)
;; do your thing here
(let ((entry ...))
;; to return it to Sytes, it's best to return a hash table
;; or an association list, so it can reference properties
;; using the dot notation, i.e.:
`(("title" . ,(blog-entry-title entry))
("body" . ,(blog-entry-body entry))))))
Defining custom URL handlers
Another way to interface with CL which might be convenient sometimes is to intercept whole calls to an URL and perhaps decide which template to execute (rather than delegate this responsibility to Sytes), or pass additional variables to the template. This would work as well (maybe even better) as a dhandler for the blog example, it's just another way to do it.
(sytes:def-url-handler (*syte* "^/blog/([0-9]+)/([0-9]+)/([0-9]+)/(.*)$"
year month date title)
;; as you can see, it's regexp-based
;; when a blog URL is encountered, it'll get here,
;; and we also conveniently get the parts of the URL
;; that we're interested in (year, month, date and title)
(let ((entry ...fetch DB entry...))
`(:template "blog/index.syt"
:variables ("title" ,(blog-entry-title entry)
"body" ,(blog-entry-body entry)))))
Notice an important thing above: the variables that we pass
to the template needs to be a plist, and in particular, variable names
should be strings rather than CL symbols. They can also be Sytes symbols,
i.e. you can pass (intern "title" :sytes.%runtime%)
, with
the advantage that you can evaluate that at read-time, but it's uglier to
type.
A custom handler may return the keyword :continue
in order
to decline and let Sytes continue handling the request normally.
Otherwise the return value should be a list of keyword-values (that's
passed to (destructuring-bind)
) and it supports the
following keywords (some are exclusive):
:template
— set the template to run. The path is relative to the Syte root directory. If this property is not returned, Sytes will decide what template to try based on the URL, as it does normally.:variables
— definitions to make available in the template. They will be only available at run-time, not at compile-time.:redirect
— when present, tells Sytes an URL to redirect to. Other values don't make sense in this case.:static-file
— serve the given file using hunchentoot:handle-static-file.:content-type
— the “Content-Type” HTTP header to set; by default it's"text/html; charset=UTF-8"
.:status
— the HTTP status code to return.:content
— the content to return; no template is run in this case. You can use this if you generate the content from the handler itself and would like Sytes to just return that.
Sytes
A Common Lisp library for building websites the easy way.