Defrest Commons Lisp URL library
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
bonkzwonil 20824af483
Merge pull request #7 from jnykopp/master
5 years ago
script Added bash script for running test suite with SBCL 7 years ago
tests Added a test where the DEFREST route consists of query-params only 7 years ago
.gitignore tag etc 11 years ago
LICENSE LICENSE 11 years ago Update 7 years ago
defrest.asd Change: Query parameters will not break route matching 7 years ago
defrest.lisp Get rid of literal function objects 5 years ago
minimal-example.lisp added minimalistic example 11 years ago


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