Parameterised decorators for easy-routes

The easy-routes library makes it easy and fast to define Rails-like HTTP routes for Hunchentoot. It has the concept of decorators which are functions that form part of the request handling sequence but not part of the main request handler. Decorator functions are usually general functions which are applicable to many request handlers, for example, to set up a database connection before handling a request.

Parameterless decorators

Most decorators are simple functions which do not take any parameters from the request handler. The DB connection decorator can be defined as below:

( defun @db ( next ) ( postmodern:with-connection *db-spec* ( funcall next )))

All decorators take the next parameter which is the function that should be called after this decorator has completed its task. The parameter is supplied by easy-routes .

A route that uses a decorator is defined like this:

( defroute api-handler ( "/api" :method :get :decorators ( @db @auth )) ... )

The :decorators keyword takes a list of decorator names in the order they need to be executed. In the example above the @db function will run, followed by the @auth function and then api-handler . Since @auth runs after @db it can assume an open database connection. Note that the next parameter is not mentioned anywhere.

Parameterised decorators

For more complex cases where the decorator needs input from the route handler, it can be defined with extra parameters like this:

( defun @check ( predicate http-error next ) ( if ( funcall predicate ) ( funcall next ) ( http-error http-error )))

The next parameter must be last in the parameter list.

With a predicate function defined like below,

( defun test-p () ... )

a route handler can be defined like this:

( defroute api-handler ( "/api" :method :get :decorators ( @db @auth ( @check test-p hunchentoot:+http-forbidden+ )) ) ... )