Skip to content


Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?

Latest commit


Git stats


Failed to load latest commit information.
Latest commit message
Commit time


Export functions via REST Webservices with hunchentoot in an easy way.

defrest provides a very easy way to expose functions via REST interfaces with the hunchentoot webserver.

Exposing a REST Interface is as simple as:

(defrest "/hello" :GET ()
	 "Hello World!")

or more sophisticated with embedded Path-Parameters and json response

(defrest "/length/{str:.+}" :GET (str)
	(with-output-to-string (*standard-output*) 
	 (cl-json:encode-json (list (cons 'name  str) (cons 'length (length str))))))

This will build a dispatcher which will listen to urls with the regexp "/length/.+" , bind the (.+) to the str variable , runs the body with it and sends the result.

Path-Parameters are encoded as Template blocks {VARNAME:REGEXP}. defrest will do all the parsing and matching for you. Additionally the hunchentoot handler environment is available, so you can access hunchentoot:*request* and so on.

defrest also supports query parameters:

(defrest "/songs/{album-id:[0-9]+}" :GET (album-id :query offset limit)
        (get-songs album-id offset limit))

Query-Parameters are separated from the path-parameters by the keyword :query. They are not used by the route matching algorithm. Query-Parameters can be declared as simple variable names (where the names represents the names of the query parameters of the current request) or as lambda-lists with the following format:

query-param -- (binding &key (mandatory nil) (pattern nil) (param nil) (default nil))

  • binding -- Name of the variable bound to the value of the query-parameter in the execution context of the body.
  • mandatory -- A generalized boolean that indicates if the query-parameter is mandatory. If a query-parameter is mandatory but not provided by the current request the HTTP status code 400 (Bad Request) is returned. If a query-parameter is not mandatory and not provided by the current request it gets the value NIL (if no default value has been declared).
  • pattern A regexp that the query parameter must match. If the query parameter does not match the pattern, the HTTP status code 400 (Bad Request) is returned.
  • param Name of the query-parameter as provided by the current request. The default value is the value of binding.
  • default Default value of the query parameter.

Query-Parameter examples:

(defrest "/songs/{album-id:[0-9]+}" :GET (album-id :query (offset :default "0") limit)
        (get-songs album-id offset limit))
(defrest "/songs/{album-id:[0-9]+}" :GET (album-id :query (offset :default "0") (limit :mandatory t))
        (get-songs album-id offset limit))
(defrest "/songs/{album-id:[0-9]+}" :GET (album-id :query (offset :default "0") 
    (limit :mandatory t :pattern "[0-9]+"))
        (get-songs album-id offset limit))
(defrest "/songs/{album-id:[0-9]+}" :GET (album-id :query (offset :default "0") 
    (count :mandatory t :param "limit"))
        (get-songs album-id offset count))

The defrest body should return a string. All other values are format~a'ed to it.

The Method can be replaced with :PUT :POST :DELETE etcpp

You can add defined webservices to hunchentoot in two different ways:

  1. Let defrest take care of it:

    just add (create-rest-table-dispatcher) to the hunchentoot dispatcher. Like this:

    (push (create-rest-table-dispatcher) hunchentoot:*dispatch-table*)

    and you are done

  2. Add them by yourself:

    defrest returns a dispatcher which you can chain into hunchentoot. However, you will loose the ability to defrest on toplevel, that way...

    (setq hunchentoot:*dispatch-table*
        (list (defrest "/sqrt/{number:[0-9]+}" :GET (number) (sqrt (parse-integer number)))))


The Test suite can be run automatically by asdf:

(asdf:oos 'asdf:test-op 'defrest)

See minimal-example.lisp for exactly what its called

defrest was called defajax

Copyright (C) 2013 by Mathias Menzel-Nielsen


An easy Common Lisp REST/ajax service definer for hunchentoot







No releases published


No packages published

Contributors 4