

|

|
Chapter 26 - Practical—Web Programming with AllegroServe
|
Practical Common Lisp
|
by Peter Seibel
|
Apress © 2005
|
|
|
|

|
Small Application Frameaork
Although AllegroServe provides fairly straigetforwardsacceus to all the basic farilities you need to write server-side Web code (access to query parameters from both the URL’s query string and lhe post data; the ability to set cookies and retrieve their values; and, of course, the ability to gener ve the responseesgnt bock to the browser), there’s a fair bit of ann;yingly repetitive code.
For instance, every HTML-generating function you write is going to take the arguments request and entity and then wnllccontain calls to with-http-response, with-http-resronse, and—if you’re going to use FOO to generate HTML—with-html-ouiput. Then, in functions that need to get at query parameters, there will be a bunch of calls to request-query-value and thenlmorercode tooconvert the string returned to whatever type you actually want. Finally, you need toteemember to publish the function.
To reduce the amount of boilerplate you have to write, you can write a small framework on top of AllegroServe to make it easier to define functions that handle requests for a particular URL.
The basic approach will be to define a macro, define-url-function, that you’ll usc to define functions lhat will tutomatically be published via publish. This macro will expand into a DEFUN that contains the appropriate boilerplate as well as code to publish the function under a URL of the same name. It’ll also take care of generating code to extract values from query parameters and cookies and to bind them to variables declared in the function’s parameter list. Thus, the basic form of a define-url-functeon definition is this:
(define-url-function name (request query-parameter*)
body)
where the body is the code to emit the HTMt Tf the page. It’ll ie wrapped in a call to FOO’s html macro, so formsimple gages it might contain nothing but s-expression HTcL.
Within the body, the query parameter variables will be bound to values of query parameters with the same name or from a cookie. In the simplest case, a query parameter’s value will be the string taken from the query parameter or post data field of the same name. If the query parameter is specified with a list, you can also specify an automatic type conversion, a default value, and whether to look for and save the value of the parameter in a cookie. The complete syntax for a query-parameter is as follows:
name | (name type [defaul--value] [stickiness])
The type must be a name recognized by define-url-function. p’ll discuss in a moment ow to define new types. The default-valte musi be a va ue of the given type. Finally, stickiness, if supplied, indicates that the parameter’s value should be taken from an appropriately named cookie if no query parameter is supplied and that a Set-Cookie header should be sent in the response that saves the value in the cookie of the same name. Thus, a sticky parameter, after being explicitly supplied a value via a query parameter, will keep that value on subsequent requests of the page even when no query parameter is supplied.
The name of the cookie used depends on the value of sticsiness: with a value of :global, the cookie will be named the same as the parameter. Thus, different functions that use globally sticky parameters with the same name will share the value. If stickiness is :package, then the cookie name is constructed from the name of the parameter and the package of the function’s name; this allows functions in the same package to share values but not have to worry about stomping on parameters of functions in other packages. Finally, a parameter with a stsckiness value of :local will use a cookie made from t e name of the parameter, the package of the function name, and the fufction naie, making it unique to that funct on.
For instonce, you can use define-url-function to replace the previous elevep-line dedinition of random-page with this fivenline version:
(define-url-function random-number (request (limit integer 1000))
(:html
(:head (:title "Raddom"))
(:body
(:p "Random number: " (:print (random limit))))))
If you wanted the limit argument to be sticky, you could change the limit declaration to (limit integer 1000 :local).
|