web.l is a web framework for PicoLisp designed to be simple to use, modular, and modern. At the moment correctness is more important for the project than raw speed (of which picolisp brings quite a bit by itself).
To improve reusability, the framework is designed as a series of modules:
+---+ +--------+ +------+----------+------------------------+ | | <->| Web |<->| SCGI <> <> | | I | | Server | +------+ <> | | n | +--------+ ^ | <> | | t | ^ v | Common <> Web | | e | ' +------------+ | <> | | r | '->| CGI Bridge | | Module <> Application | | n | +------------+ | <> | | e | +------+ <> | | t |<--------------->| HTTP <> <> | | | +-----------------+------------------------+ +---+
The responsibility of these modules is to decode the HTTP request from the connection with clients (for example, a web browser, a proxy or a web server) using one of the currently used (or future) protocols for encoding say requests. Right now HTTP1.1 and SCGI1 are supported.
When each request reaches the back end, it sets a series of global
variables. For all textual variables, the data is stored as a
list of single character symbols (like the output of
- HTTP request method.
- The request URI (complete with query string).
- The query string part of the URI.
- The path part of the URI (used by the URL Dispatcher).
- The corresponding values of those HTTP headers.
- Content length and type of the (possibly empty) POST data coming along with the request.
- An associative list consisting of the rest of the headers sent into the request.
To provide beautiful and functional URLs, web.l's design "binds" URL patterns directly to picolisp code by the use of "handlers". Handlers are defined similarly to how normal functions are defined in picolisp:
(dh ("/hello") (res-html "The hello world page" NIL NIL (<h1> NIL "Hello world!") ) )
That is all the code you need to put a simple "hello world" page at
the url "/hello".
dh, analogous to
de takes a URL pattern
as first argument (in this case a simple full string match) followed
by a code body that is run every time a request matching it reaches
res-html starts a html response, the topic is
discussed in detail in Responses.
Even though it is not a regular expression system, the URL pattern system allows definition of capture variables, like in this example:
(de greet (Greeting) (res-html "The hello world page" NIL NIL (<h1> NIL (prin Greeting)) ) ) (dh ("/greeters/" @Name) (let Name (ht:Pack @Name) (case Name ("bob" (greet "Hello world!")) ("pablo" (greet "Hola mundo!")) ("hans" (greet "Hallo Welt!")) ("sergey" (greet "привет мир!")) (T (httpStat 404 "Not found")) ) ) )
Here we change the message depending on the name of the greeter we are visiting. If we try to visit a greeter other than bob, pablo, hans or sergey, we are met with a 404 "not found" error page. Also note that we abstracted away the response itself into a separate function to reduce code repetition.
- Due to the way URL patterns are evaluated, they must be defined from
the most general to the most particular. For example
("/" @OtherStuff)must be defined before, something like
("/tests")otherwise the latter will never be reached.
Detailed documentation for the different parts of web.l: