source: project/release/4/awful/extra/awful.wiki @ 20690

Last change on this file since 20690 was 20690, checked in by Mario Domenech Goulart, 9 years ago

awful: require the regex egg. Version bumped to 0.27.0

File size: 62.1 KB
Line 
1== Awful
2
3[[toc:]]
4
5=== Description
6
7awful provides an application and an extension to ease the development of web-based applications.
8
9Here's a short summary of awful features:
10
11* Straightforward interface to databases (currently supported are postgresql and sqlite3)
12* Support for page dispatching via regular expressions
13* Easy access to query string and body request variables from HTTP requests
14* Ajax support via [[http://jquery.com/|JQuery]]
15* Reasonably flexible (several configuration parameters)
16* Compiled pages made easy
17* Session inspector
18* Web REPL
19
20==== Screencasts
21
22Here are some screencasts about awful:
23
24; [[http://wiki.call-cc.org/video/awful.ogv|Awful in 35s]] : a 35 seconds video showing the installation of the awful egg and the development of a "hello, world" example
25
26; [[http://wiki.call-cc.org/video/awful-guess.ogv|Number guessing game]] : a video demonstrating the development of a very simple number guessing game using ajax and the web REPL
27
28
29=== Author
30
31[[/users/mario-domenech-goulart|Mario Domenech Goulart]]
32
33
34=== Requirements
35
36The following eggs are required:
37
38* [[/egg/spiffy|spiffy]]
39* [[/egg/spiffy-cookies|spiffy-cookies]]
40* [[/egg/spiffy-request-vars|spiffy-request-vars]]
41* [[/egg/html-tags|html-tags]]
42* [[/egg/html-utils|html-utils]]
43* [[/egg/json|json]]
44* [[/egg/http-session|http-session]]
45
46
47=== Components
48
49awful is composed by two parts: an application, which can be thought as a web server; and an extension, which provides most of the supported features.
50
51=== A "Hello, world!" example
52
53Here's a "Hello, world!" example to be run by awful ({{hello-world.scm}}).
54
55<enscript highlight=scheme>
56(use awful)
57
58(define-page (main-page-path)
59  (lambda ()
60    "Hello, world!"))
61</enscript>
62
63To run this example, execute:
64
65  $ awful hello-world.scm
66
67Then access localhost:8080 using your favourite web browser.
68
69Without any configuration, awful listens on port 8080.  Since awful uses Spiffy behind the scenes, you can configure the web server parameters using Spiffy's.
70
71{{define-page}} is the primitive procedure to define pages.  In the simplest case, it takes as arguments a path to the page and a procedure to generate the page contents. The path to the page you use as the first argument is the same to be used as the path part of the URL you use to access the page.
72
73In the example we use the {{main-page-path}} parameter, which is one of the awful configuration parameters.  The default is {{"/"}}.
74
75If you look at the page source code, you'll see that awful created an HTML page for you.  Awful uses the [[/egg/html-utils|html-tags]]'s {{html-page}} procedure behind the scenes.  You can customize the page either by passing {{html-page}}'s keyword parameters to {{define-page}} or by setting the {{page-template}} parameter with your favourite procedure to generate pages. {{page-template}} is a one-mandatory-argument procedure which receives the page contents and returns a string representing the formatted contents. {{define-page}} would still pass the {{html-page}} keyword parameters, so you can make use of them (the {{page-template}} procedure should be defined considering them -- if you don't need them, just ignore them by defining {{(lambda (contents . args) ...)}}).
76
77You can also use some global page-related parameters if all pages use the same CSS, doctype and charset ({{page-css}}, {{page-doctype}} and {{page-charset}}, respectively).
78
79
80An alternative way to write Awful '''scripts''' is by using the {{#!/path/to/awful}} shebang line.  Example:
81
82<enscript highlight=scheme>
83#! /usr/bin/awful
84
85(use awful)
86
87(define-page (main-page-path)
88  (lambda ()
89    "Hello, world!"))
90</enscript>
91
92Then you just need to run your script (assuming the file has execution permissions):
93
94  $ ./hello-world.scm
95
96
97=== Accessing request variables
98
99Awful provides a procedure ({{$}}) to access variables from the request, both from the query string (GET method) and from the request body (e.g., POST method).
100
101Here's a modified "Hello, world!" example to greet some person instead of the whole world:
102
103<enscript highlight=scheme>
104(use awful)
105
106(define-page (main-page-path)
107  (lambda ()
108    (++ "Hello, " ($ 'person "world") "!")))
109</enscript>
110
111The {{++}} procedure is an alias to {{string-append}} (name inspired by Haskell's operator to concatenate strings).
112
113So, restart the web server to reload the code, then access the main page using an argument, represented by the {{person}} query string variable: {{http://localhost:8080/?person=Mario}}. You'll see a page showing {{Hello, Mario!}}.
114
115
116=== Re-evaluating the code by reloading the page
117
118When we upgraded our "Hello, world!" example to the improved one which can use an argument passed through the URL, we needed to modify the code and restart the web server to reload the application code.  Awful provides a way to reload the code via URL without restarting the server.  To do that, we can define a special page whose handler just reloads the code:
119
120<enscript highlight=scheme>
121(define-page "/reload"
122  (lambda ()
123    (load-apps (awful-apps))
124    "Reloaded"))
125</enscript>
126
127and restart the awful server.  Now, whenever you want to reload the application code, access {{http://localhost:8080/reload}}.
128
129You can control which IP numbers can access the reload page by using the {{page-access-control}} parameter.  For example, allowing only the localhost to reload the apps:
130
131<enscript highlight=scheme>
132(page-access-control
133 (lambda (path)
134   (if (equal? path "/reload")
135       (member (remote-address) '("127.0.0.1"))
136       #t)))
137</enscript>
138
139When used in development mode (see the {{--development-mode}} command line option for the awful application server), awful automatically defines a {{/reload}} path (available to any host) for reloading all the applications.
140
141
142=== Using ajax
143
144Awful provides a way to (hopefully) make the use of ajax straightforward for web applications.
145
146By default, the ajax support is disabled, but it can be easily globally enabled by setting the {{enable-ajax}} parameter to {{#t}}.  When you enable ajax via {{enable-ajax}}, all the pages defined via {{define-page}} will be linked to the JQuery javascript library. If you want just a couple of pages to have ajax support (i.e., not global ajax support), you can use the {{use-ajax}} keyword parameter for {{define-page}}, so only the pages defined with {{use-ajax: #t}} have ajax support.
147
148When you have ajax enabled and you want to disable it for specific pages, you can pass {{#f}} as the value for the {{define-page}} keyword parameter {{no-ajax}}.
149
150The URL of the JQuery file can be customized by setting the {{ajax-library}} parameter (the default is Google's API JQuery file version 1.4.2).
151
152So, if we now change our code to
153
154<enscript highlight=scheme>
155(use awful)
156
157(define-page (main-page-path)
158  (lambda ()
159    (++ "Hello, " ($ 'person "world") "!"))
160  use-ajax: #t)
161</enscript>
162
163and reload the application, we'll have our page linked to JQuery.
164
165Awful provides some procedures to do ajax.  We start by the more generic one ({{ajax}}) to reply the page greetings when we click "Hello, <person>!".
166
167<enscript highlight=scheme>
168(use awful html-tags)
169
170(define-page (main-page-path)
171  (lambda ()
172    (ajax "greetings" 'greetings 'click
173          (lambda ()
174            (<b> "Hello, awful!"))
175          target: "greetings-reply")
176    (++ (<a> href: "#"
177             id: "greetings"
178             (++ "Hello, " ($ 'person "world") "!"))
179        (<div> id: "greetings-reply")))
180  use-ajax: #t)
181</enscript>
182
183The {{ajax}} procedure uses at least four arguments:
184
1851. The URL path to the server-side handler (a string).  This path is relative to {{ajax-namespace}} parameter (default is {{ajax}}.  So, in the example, we'll have {{/ajax/greetings}} as the ajax path to be generated if we pass {{ajax}} as the first argument.
186
1872. The ID of the DOM element to observe.
188
1893. The event to be handled
190
1914. The procedure to be run on the server-side.
192
193So, in the example, {{ajax}} will bind the fourth argument (the procedure) to the first argument (the path) on the server side. Then it will add javascript code to the page in order to wait for click events for the element of ID {{greetings}}.  When we click "Hello, <person>!", we'll get {{Hello, awful!}} printed on the page as reply.  {{ajax}} updates the DOM element whose id is the value of the {{target}} keyword parameter ({{"greetings-reply"}}, in the example).
194
195For the very specific case of creating links that execute server side code when clicked, awful provides the {{ajax-link}} procedure.  So our example could be coded like:
196
197<enscript highlight=scheme>
198(use awful)
199
200(define-page (main-page-path)
201  (lambda ()
202    (++ (ajax-link "greetings" 'greetings
203                   (lambda ()
204                     (<b> "Hello, awful!"))
205                   target: "greetings-reply")
206        (<div> id: "greetings-reply")))
207  use-ajax: #t)
208</enscript>
209
210
211
212=== Adding arbitrary javascript code to pages
213
214Awful provides a procedure which can be used to add arbitrary javascript code to the page. It's called {{add-javascript}}.  Here's an example using javascript's {{alert}} and our "Hello, world!" example:
215
216<enscript highlight=scheme>
217(use awful)
218
219(define-page (main-page-path)
220  (lambda ()
221    (add-javascript "alert('Hello!');")
222    (++ (ajax-link "greetings" 'greetings
223                   (lambda ()
224                     (<b> "Hello, awful!"))
225                   target: "greetings-reply")
226        (<div> id: "greetings-reply")))
227  use-ajax: #t)
228</enscript>
229
230
231
232=== Database access
233
234To access databases, you need some of the awful eggs which provide database access.  Currently, these are the possible options:
235
236* [[/egg/awful-postgresql|awful-postgresql]] (for Postgresql databases, using the [[/egg/postgresql|postgresql]] egg)
237
238* [[/egg/awful-sqlite3|awful-sqlite3]] (for Sqlite3 databases, using the [[/egg/sqlite3|sqlite3]] egg)
239* [[/egg/awful-sql-de-lite|awful-sql-de-lite]] (for Sqlite3 databases, using the [[/egg/sql-de-lite|sql-de-lite]] egg)
240
241As with ajax, database access is not enabled by default.  To enable it, you need to pick one the awful database support eggs and call the {{enable-db}} procedure.  Since version 0.10, and differently from the {{enable-*}} parameters, {{enable-db}} is a zero-argument procedure provided by each of awful database-support eggs.  So, if you use {{awful-postgresql}}, the {{enable-db}} procedure will automatically set up awful to use a postgresql database.
242
243Additionally, to access the db, you need to provide the credentials.  You can provide the credentials by setting the {{db-credentials}} parameter.  See the documentation for the eggs corresponding to the database type you are using ([[/egg/postgresql|postgresql]] for Postgresql and [[/egg/sqlite3|sqlite3]] or [[/egg/sql-de-lite|sql-de-lite]] for Sqlite3.)
244
245To actually query the database, there's the {{$db}} procedure, which uses as arguments a string representing the query and, optionally, a default value (a keyword parameter) to be used in case the query doesn't return any result. {{$db}} returns a list of lists. Below is an usage example:
246
247<enscript highlight=scheme>
248(use awful awful-postgresql)
249
250(enable-db)
251(db-credentials '((dbname . "my-db")
252                  (user . "mario")
253                  (password . "secret")
254                  (host . "localhost")))
255
256(define-page "db-example"
257  (lambda ()
258    (with-output-to-string
259      (lambda ()
260        (pp ($db "select full_name, phone from users"))))))
261</enscript>
262
263''Hint'': for Sqlite3 databases, {{db-credentials}} should be the path to the database file.
264
265There's also the {{$db-row-obj}} procedure for when you want to access the results of a query by row name.  {{$db-row-obj}} returns a procedure of two arguments: the name of the field and, optionally, a default value to be used in case the field value is {{#f}}.
266
267<enscript highlight=scheme>
268(define-page "db-example"
269  (lambda ()
270    (let ((& ($db-row-obj "select full_name, phone from users where user_id=1")))
271      (<p> "Full name: " (& 'full_name))
272      (<p> "Phone: " (& 'phone)))))
273</enscript>
274
275''Warning'': currently {{$db-row-obj}} is only implemented for Postgresql.
276
277If you need more flexibility to query the database, you can always use the {{(db-connection}}) parameter to get the database connection object and use it with the procedures available from the your favorite database egg API.
278
279
280=== Login pages and session
281
282Awful provides a very basic (awful?) support for creating authentication pages.
283
284The basic things you have to do is:
285
2861. Enable the use of sessions:
287
288<enscript highlight=scheme>
289(enable-session #t)
290</enscript>
291
2922. Set the password validation parameter.  This parameter is a two argument procedure (user and password) which returns a value (usually {{#t}} or {{#f}}) indicating whether the password is valid for the given user.  The default is a password which returns {{#f}}.  Let's set it to a procedure which returns {{#t}} is the user and the password are the same:
293
294<enscript highlight=scheme>
295(valid-password?
296  (lambda (user password)
297    (equal? user password)))
298</enscript>
299
3003. Define a login trampoline, which is an intermediate page accessed when redirecting from the login page to the main page.
301
302<enscript highlight=scheme>
303(define-login-trampoline "/login-trampoline")
304</enscript>
305
3064. Create a login page.  Awful provides a simple user/password login form ({{login-form}}), which we are going to use.  Here's our full example so far (using the basic "Hello, world!" as main page).
307
308<enscript highlight=scheme>
309(use awful)
310
311(enable-session #t)
312
313(define-login-trampoline "/login-trampoline")
314
315(valid-password?
316  (lambda (user password)
317    (equal? user password)))
318
319(define-page (main-page-path)
320  (lambda ()
321    "Hello world!"))
322
323(define-page (login-page-path)
324  (lambda ()
325    (login-form))
326  no-session: #t)
327</enscript>
328
329That's the very basic we need to set an auth page.  If the password is valid for the given user, awful will perform a redirect to the main page ({{main-page-path}} parameter) passing the {{user}} variable and its value in the query string .  If the password is not valid, awful will redirect to the login page ({{login-page-path}} parameter) and pass the following variables and values:
330
331; {{reason}} : the reason why awful redirected to the login page. It may be {{invalid-password}}, for when the password is invalid for the given user; or {{invalid-session}} for when the session identifier is not valid (e.g., the session expired).
332
333; {{attempted-page}} : the URL path to page the user tried to access, but couldn't because either he/she was not logged in or he/she provided an invalid session identifier.
334
335; {{user}} : the user used for the form user field.
336
337Now we're gonna change our main page to store the user in the session and retrieve it to make the greetings message:
338
339<enscript highlight=scheme>
340(define-page (main-page-path)
341  (lambda ()
342    ($session-set! 'user ($ 'user))
343    (++ "Hello " ($session 'user "world") "!")))
344</enscript>
345
346Here we can see the two procedures to access the session: {{$session}} and {{$session-set!}}.
347
348{{$session-set!}} accepts two arguments: the first one is the name of the session variable and the second one is its value.
349
350{{$session}} takes the name of the session variable as argument and returns its session value.  We can optionally use a second argument to specify a default value, in case the session variable is not bound or is {{#f}}.
351
352
353=== Session inspector
354
355Awful provides a session inspector, so we can easily see the session contents for a given session identifier.  By default, the session inspector is disabled.  We can enabled it using the {{enable-session-inspector}} procedure, passing the session inspector URL path as argument:
356
357<enscript highlight=scheme>
358(enable-session-inspector "session-inspector")
359</enscript>
360
361Now, if you log in and try to access {{http://localhost:8080/session-inspector}}, you'll get ... an access denied page.
362
363Awful provides a way to control access to the session inspector ({{session-inspector-access-control}} parameter).  The {{session-inspector-access-control}} parameter is an one-argument procedure which returns {{#f}} or some other value to indicate whether the access to the session inspector is allowed or not. By default, it blocks all access.  Let's configure it so we can access the session inspector from the local machine (whose IP number is 127.0.0.1):
364
365<enscript highlight=scheme>
366(session-inspector-access-control
367 (lambda ()
368   (member (remote-address) '("127.0.0.1"))))
369</enscript>
370
371Regarding to the access denied message, you can customize it by setting the {{session-inspector-access-denied-message}}.
372
373Now we can access {{http://localhost:8080/session-inspector}} and see the session contents.
374
375''Note'': if {{enable-session-cookie}} is {{#f}}, you need to pass the session identifier in the query string (e.g., {{http://localhost:8080/session-inspector?sid=the-session-cookie-here}}).
376
377Here's a screenshot:
378
379[[image:http://parenteses.org/mario/img/awful/session-inspector.png|Awful session inspector]]
380
381When {{enable-session}} is {{#t}} and the {{--development-mode}} option is given to the awful application server, the session inspector is automatically enabled and is avaliable from {{/session-inspector}}.
382
383=== Web REPL
384
385For further run-time, server-side web hacking, awful provides a REPL that you can use via web browser.
386
387The web REPL can use either a plain HTML textarea for the input area or a more featureful editor (based on [[http://codemirror.net|codemirror]]).  By default, the web REPL uses the ''fancy'' editor.
388
389The activation and control access are basically the same as for the session inspector.  The relevant procedure and parameters are:
390
391* {{enable-web-repl}}
392* {{web-repl-access-control}}
393* {{web-repl-access-denied-message}}
394* {{enable-web-repl-fancy-editor}}
395* {{web-repl-fancy-editor-base-uri}}
396
397Here's a screenshot (using the fancy editor):
398
399[[image:http://parenteses.org/mario/img/awful/fancy-web-repl.png|Awful web REPL]]
400
401When the {{--development-mode}} option is given to the awful application server, the web REPL is automatically enabled and is avaliable from {{/web-repl}}. The awful application server also accepts the {{--disable-web-repl-fancy-editor}} command line option to disable the web REPL fancy editor.
402
403
404=== Pages access control
405
406To allow/deny access to pages, you can use the {{page-access-control}} parameter.  It's an one-argument procedure (the page path) which can be set to determine if the access to the page is allowed or not.
407
408The example bellow shows a very silly access control to the main page: it only allows the access when the value of the request variable {{user}} is {{"mario"}}:
409
410<enscript highlight=scheme>
411(use awful)
412
413(enable-session #t)
414
415(define-login-trampoline "/login-trampoline")
416
417(valid-password?
418 (lambda (user password)
419   (equal? user password)))
420
421(page-access-control
422 (lambda (path)
423   (or (member path `(,(login-page-path) "/login-trampoline")) ;; allow access to login-related pages
424       (and (equal? ($ 'user) "mario")
425            (equal? path (main-page-path))))))
426
427(define-page (main-page-path)
428  (lambda ()
429    "Hello world"))
430
431(define-page (login-page-path)
432  (lambda ()
433    (login-form))
434  no-session: #t)
435</enscript>
436
437You can customize the access denied message by setting the {{page-access-denied-message}} with an one-argument procedure (the page path).
438
439
440=== Compiled pages
441
442Since Chicken is a compiler and our pages are Chicken code, we can compile them to have faster pages.  We just need to compile our app and pass the generated {{.so}} to the {{awful}} application:
443
444  $ csc -s hello-world.scm
445  $ awful hello-world.so
446
447
448
449=== Multiple applications support
450
451To be able to deploy multiple awful applications with different configurations under the same server, use Spiffy access files.  See Spiffy's [[/egg/spiffy#access-files|access files documentation]] for further details.
452
453
454=== The awful application server
455
456Awful consists of an application server and an extension module.  The awful application server is a command line program whose usage is:
457
458 $ awful --help
459 awful [ -h | --help ]
460 awful [ -v | --version ]
461 awful [ --development-mode ] [ --disable-web-repl-fancy-editor ] [ --ip-address=<ip address> ] [ --port=<port number> ] [ <app1> <app2> ... ]
462
463{{<app1> <app2> ...}} are files containing code to be loaded by the awful application server.
464
465{{--ip-address}} can be used to bind the web server to the given IP address.
466
467{{--port}} can be used to make the web server listen to the given port.
468
469{{--ip-address}} and {{--port}} take precedence over the Spiffy parameters to specify the server IP address ({{server-bind-address}}) and port ({{server-port}}).
470
471The {{--development-mode}} option is intended to be used during the development of your web application.  It's not recommended to run awful with {{--development-mode}} in production.  The development mode enables the web REPL and the session inspector (when {{enable-session}} is {{#t}}) for the localhost, prints error messages and backtraces to the client (e.g., web browser) and HTTP server debugging messages to the {{current-error-port}}.  It also makes the {{/reload}} path available for reloading awful applications.
472
473When in development mode, the web REPL and the session inspector are available from the {{/web-repl}} and {{/session-inspector}} paths.
474
475If you enable the development mode you can still use {{enable-web-repl}} and {{enable-session-inspector}} to customize their respective paths and access control procedures (although the development mode always allows access to web REPL and session inspector for the localhost).
476
477The {{--disable-web-repl-fancy-editor}} command line option disables the web REPL fancy editor.
478
479
480=== Deploying awful
481
482See the [[/deploying-awful|Deploying Awful]] page on the [[http://wiki.call-cc.org|Chicken Wiki]].
483
484
485=== List of user configurable parameters
486
487==== Debugging
488
489<parameter>(debug-file [file path])</parameter>
490
491If {{#f}}, indicates that debugging should be disabled.  When set to a string, it should be the path to the file where the debug messages go (when {{debug}} or {{debug-pp}} is used.)
492
493The default value is {{#f}}.
494
495
496<parameter>(debug-db-query? [boolean])</parameter>
497
498When not {{#f}}, all queries passed to {{$db}} and to {{$db-row-obj}} are printed to the debug file.
499
500The default value is {{#f}}.
501
502
503<parameter>(debug-db-query-prefix [string])</parameter>
504
505Prefix to be used for queries debugging when {{debug-db-query}} is not {{#f}}.
506
507The default value is {{""}}.
508
509
510<parameter>(debug-resources [boolean])</parameter>
511
512When {{#t}}, enables debugging of awful's resources table (an alist mapping paths (or regexes) and vhost paths to their corresponding procedures to be executed on the server side upon request).  The debugging data is sent to the file pointed by {{debug-file}}.  The default value is {{#f}}.
513
514
515==== Database
516
517<parameter>(db-credentials [boolean or list])</parameter>
518
519Credentials to be used to access the database (see the documentation for the egg corresponding to the database backend you selected.)  When {{#f}}, no database access is performed.
520
521The default value is {{#f}}.
522
523
524==== Ajax
525
526<parameter>(ajax-library [string])</parameter>
527
528URL or path to the ajax library (currently only [[http://jquery.com|JQuery]] is supported.)
529
530The default value is {{"http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"}}
531
532
533<parameter>(enable-ajax [boolean])</parameter>
534
535When {{#t}}, makes {{define-page}} link the {{ajax-library}} to the generated page.  It's effect is global, that is, once {{enable-ajax}} is set to {{#t}}, all pages defined via {{define-page}} will be linked to the ajax library, unless when the {{no-ajax}} keyword parameter is explicitly set.
536
537The default value is {{#f}}
538
539
540<parameter>(ajax-namespace [string])</parameter>
541
542Name to be used as a namespace for ajax URL paths.
543
544The default value is {{"ajax"}}.
545
546
547<parameter>(ajax-invalid-session-message [string])</parameter>
548
549The message to be used when attempting the make an ajax call using an invalid session identifier.
550
551The default value is {{"Invalid session"}}.
552
553
554
555==== Sessions
556
557<parameter>(enable-session [boolean])</parameter>
558
559When {{#t}}, session support is enabled.
560
561The default value is {{#f}}.
562
563
564<parameter>(enable-session-cookie [boolean])</parameter>
565
566When {{#t}}, awful uses cookies to store the session identifier.  Otherwise, the session identifier is passed as a value in the query string or in the request body. The default value is {{#t}}.
567
568
569<parameter>(session-cookie-name [string])</parameter>
570
571The name of the cookie for storing the session identifier.  The dafult value is {{"awful-cookie"}}.
572
573
574==== Access control
575
576<parameter>(page-access-control [procedure])</parameter>
577
578An one-argument (URL path of the current page) procedure which tells whether the access to the page is allowed or not.
579
580The default value is {{(lambda (path) #t)}}.
581
582
583<parameter>(page-access-denied-message [procedure])</parameter>
584
585An one-argument (URL path of the current page) procedure which returns the access denied message.
586
587The default value is {{(lambda (path) (<h3> "Access denied."))}}.
588
589
590<parameter>(valid-password? [procedure])</parameter>
591
592A two-argument (user and password) procedure which indicates whether the given password is valid for the given user.
593
594The default value is {{(lambda (user password) #f)}}.
595
596
597==== Pages
598
599<parameter>(page-doctype [string])</parameter>
600
601The doctype (see the [[/egg/doctype|doctype]] egg) to be applied to all pages defined by {{define-page}}.  It can be overwritten by {{define-page}}'s {{doctype}} keyword parameter.
602
603The default value is {{""}}.
604
605
606<parameter>(page-css [boolean or string])</parameter>
607
608The CSS file to be linked by all pages defined by {{define-page}}.  It can be overwritten by {{define-page}}'s {{css}} keyword parameter.  See [[/egg/html-utils|html-utils]]'s {{html-page}} procedure to know about the {{css}} keyword parameter syntax.
609
610The default value is {{#f}} (no CSS).
611
612
613<parameter>(page-charset [boolean or string])</parameter>
614
615The page charset to be used by all pages defined by {{define-page}}.  It can be overwritten by {{define-page}}'s {{charset}} keyword parameter.
616The default value is {{#f}} (no explicit charset).
617
618
619<parameter>(page-template [procedure])</parameter>
620
621An one-mandatory-argument procedure to be used by {{define-page}} (unless {{define-page}}'s {{no-template}} keyword parameter is set to {{#f}}) to generate HTML pages. Although this procedure can take only one mandatory argument, the following keyword arguments are passed:
622
623* css
624* title
625* doctype
626* headers
627* charset
628* no-ajax
629* no-template
630* no-session
631* no-db
632
633The default value is {{html-page}} (see the [[/egg/html-utils|html-utils]] egg documentation.)
634
635
636<parameter>(page-exception-message [procedure])</parameter>
637
638An one-argument procedure to be used when an exception occurs while {{define-page}} tries to evaluate its contents.
639
640The default value is {{(lambda (exn) (<h3> "An error has accurred while processing your request."))}}
641
642
643
644==== Page paths
645
646<parameter>(main-page-path [string])</parameter>
647
648The URL path to the app main page.
649
650The default value is {{"/"}}.
651
652
653<parameter>(app-root-path [string])</parameter>
654
655The base path to be used by the application.  All the pages defined by {{define-page}} will use {{app-root-path}} as the base directory.  For example, if {{app-root-path}} is set to {{"/my-app"}} and {{"my-page"}} is used as first argument to {{define-page}}, the page would be available at {{http://<server>:<port>/my-app/my-page}}.
656
657The default value is {{"/"}}.
658
659
660<parameter>(login-page-path [string])</parameter>
661
662The URL path for the login page.  When creating a login page, be sure to set the {{no-session}} keyword parameter for {{define-page}} to {{#t}}, otherwise you'll get an endless loop.
663
664The default value is {{"/login"}}.
665
666
667
668==== Headers
669
670<parameter>(awful-response-headers [alist])</parameter>
671
672An alist to specify the headers to be used in the response.  If the {{content-length}} header is not provided, awful will calculate it automatically.
673
674Here's an example:
675
676<enscript highlight=scheme>
677#!/usr/bin/awful
678
679(use awful)
680
681(define (define-json path body)
682  (define-page path
683    (lambda ()
684      (awful-response-headers '((content-type "text/json")))
685      (body))
686    no-template: #t))
687
688
689(define-json (main-page-path)
690  (lambda ()
691    "{a: 1}"))
692</enscript>
693
694
695
696==== Web REPL
697
698<parameter>(web-repl-access-control [procedure])</parameter>
699
700A no-argument procedure to control access to the web REPL.
701
702The default value is {{(lambda () #f)}}.
703
704
705<parameter>(web-repl-access-denied-message [string])</parameter>
706
707Message to be printed when the access to the web REPL is denied.
708
709The default value is {{(<h3> "Access denied.")}}.
710
711
712<parameter>(enable-web-repl-fancy-editor [boolean])</parameter>
713
714Indicates whether the web REPL should use a fancier editor for the input area.  The editor is based on [[http://codemirror.net|codemirror]].  Without the fancy editor, the input area is a simple HTML textarea.  The default value for {{use-fancy-editor}} is {{#t}}.
715
716
717<parameter>(fancy-editor-base-uri [string])</parameter>
718
719The URI which indicates the fancy editor source files (javascript and CSS) location.  The default value is {{http://parenteses.org/awful/codemirror}}.
720
721
722
723==== Session inspector
724
725<parameter>(session-inspector-access-control [procedure])</parameter>
726
727A no-argument procedure to control access to the session inspector.
728
729The default value is {{(lambda () #f)}}.
730
731
732<parameter>(session-inspector-access-denied-message [string])</parameter>
733
734Message to be printed when the access to the session inspector is denied.
735
736The default value is {{(<h3> "Access denied.")}}.
737
738
739==== Javascript
740
741<parameter>(enable-javascript-compression [boolean])</parameter>
742
743Enable javascript compression support.  When enabled the compressor set by {{javascript-compressor}} is used.
744
745The default value is {{#f}}.
746
747
748<parameter>(javascript-compressor [procedure])</parameter>
749
750An one-argument procedure (the javascript code) which return the given javascript code compressed.  Only used when {{enable-javascript-compression}} is not {{#f}}.
751
752The default value is the {{identity}} procedure.
753
754A possible value for {{javascript-compressor}} is {{jsmin-string}} (see the [[/egg/jsmin|jsmin]] egg.)
755
756
757
758=== List of read-only parameters available to users
759
760Note: these parameters should not be explicitly set and when their use is needed, it's a string sign you're doing something you shouldn't (except for {{db-connection}}, which can be used by procedures from the [[/egg/postgresql|postgresql]] egg API).
761
762
763<parameter>(http-request-variables)</parameter>
764
765The per-request value returned by [[/egg/spiffy-request-vars|spiffy-request-vars]]'s {{request-vars}}.
766
767
768<parameter>(db-connection)</parameter>
769
770A per-request databaseconnection object.  The connection is automatically opened and closed by awful in a per-request basis (unless databases are not being used the {{no-db}} keyword parameter for {{define-page}} is {{#t}}.)
771
772
773<parameter>(page-javascript)</parameter>
774
775Javascript code to be added to the pages defined by {{define-page}}.
776
777
778<parameter>(sid)</parameter>
779
780The session identifier.
781
782
783<parameter>(awful-apps)</parameter>
784
785The list of awful applications, as given to the awful server when invoked from the command line.
786
787
788<parameter>(development-mode?)</parameter>
789
790Indicates whether awful is running in development mode (see the {{--development-mode}} command line option for the awful application server).
791
792
793
794=== List of procedures
795
796
797==== Miscelaneous
798
799<procedure>(++ string1 string2 ... stringn)</procedure>
800
801A shortcut to {{string-append}}.
802
803
804<procedure>(concat args #!optional (sep ""))</procedure>
805
806Convert {{args}} to string and intersperse the resulting strings with {{sep}}.
807
808
809<procedure>(awful-version)</procedure>
810
811Return the awful version (a string).
812
813
814==== Javascript
815
816<procedure>(include-javascript . files)</procedure>
817
818A shortcut to {{(<script> type: "text/javascript" src: file)}}.
819
820
821<procedure>(add-javascript . code)</procedure>
822
823Add arbitrary javascript code to the pages defined by {{define-page}} and {{define-session-page}}.
824
825
826==== Debugging
827
828<procedure>(debug . args)</procedure>
829
830Print {{args}}, concatenated, to the file {{debug-file}}.
831
832
833<procedure>(debug-pp arg)</procedure>
834
835Pretty-print {{arg}} to the file {{debug-file}}.
836
837
838
839==== Sessions and authentication
840
841<procedure>($session var #!optional default)</procedure>
842
843Return the value of {{var}} in the session (or {{default}} if {{var}} does not exist or is {{#f}}).
844
845
846<procedure>($session-set! var #!optional val)</procedure>
847
848If {{var}} is a quoted symbol, set the value of {{var}} to {{val}}.  If {{val}} is not provided, {{var}} will have its value set to {{#f}}.
849
850{{var}} can be an alist mapping session variable names to their corresponding values.
851
852Examples:
853
854<enscript highlight=scheme>
855($session-set! 'foo "foo value")
856
857($session-set! '((foo . "foo value")
858                 (bar . "bar value")
859                 (baz . "baz value")))
860</enscript>
861
862
863<procedure>(link url text . rest)</procedure>
864
865Return a session-aware HTML code for a link, using the {{<a>}} procedure from [[/egg/html-tags|html-tags]].
866
867The {{rest}} arguments are the same as the ones for the {{<a>}} procedure from [[/egg/html-tags|html-tags]], plus the following:
868
869; {{no-session}} : a boolean.  If {{#t}}, forces {{link}} to ignore the session even when {{enable-session}} is {{#t}}.
870; {{arguments}} : an alist mapping variable names to their corresponding values, to be passed to uri-common's {{form-urlencode}} procedure.
871; {{separator}} : the value to the {{separator}} keyword argument to be passed to to uri-common's {{form-urlencode}} procedure.
872
873When {{enable-session}} is {{#t}}, {{link}} automatically encodes the session identifier in the URI (unless {{no-session}} is {{#t}}).
874
875
876<procedure>(form contents . rest)</procedure>
877
878Return a session-aware HTML code for a form, using the {{<form>}} procedure from [[/egg/html-tags|html-tags]].
879
880The {{rest}} arguments are the same as the ones for the {{<form>}} procedure from [[/egg/html-tags|html-tags]], plus {{no-session}}, a boolean.  If {{no-session}} is {{#t}}, it forces {{form}} to ignore the session even when {{enable-session}} is {{#t}}.
881
882When {{enable-session}} is {{#t}}, {{form}} automatically generates a hidden input field to pass the session identifier (unless {{no-session}} is {{#t}}).
883
884
885<procedure>(define-login-trampoline path #!key vhost-root-path hook)</procedure>
886
887Define a trampoline -- an intermediate page accessed when redirecting from the login page to the main page.
888
889
890<procedure>(login-form #!key (user-label "User: ") (password-label "Password: ") (submit-label "Submit") (refill-user #t))</procedure>
891
892Return a user/password login form (e.g., for using in authentication pages).
893
894When the {{refill-user}} is {{#t}}, the User field is reffiled with the value from the {{user}} query string value when either the session or the password is invalid.
895
896The {{user-label}}, {{password-label}} and {{submit-label}} keyword parameters are labels to be used for the user, password and submit form widgets, respectively.
897
898
899
900==== Request variables and values
901
902<procedure>($ var #!optional default/converter)</procedure>
903
904Return the HTTP request value for the given variable {{var}}.  The variable is looked for in both the query string (GET method) and request body (e.g., POST method).  See the documentation for the procedure returned by [[/eggref/4/spiffy-request-vars|spiffy-request-vars]]'s {{request-vars}} for further details.
905
906
907==== Database access
908
909<procedure>($db q #!key default values)</procedure>
910
911Execute the given query ({{q}}) on the database and return the result as a list of lists or {{default}} if the result set is empty.
912
913The {{values}} keyword parameter (a list) is a list of values to replace the placehoders in the query.
914
915Example:
916
917<enscript highlight=scheme>
918($db "insert into foo (bar, baz) values (?, ?)" values: '("bar-val" "baz-val"))
919</enscript>
920
921<procedure>($db-row-obj q)</procedure>
922
923Execute the given query {{q}} on the database and return an one-argument procedure which takes as argument the name of the database field to get the value.
924
925Example:
926
927<enscript highlight=scheme>
928(let ((& ($db-row-obj "select full_name, phone from users where user_id=1")))
929  (<p> "Full name: " (& 'full_name))
930  (<p> "Phone: " (& 'phone)))
931</enscript>
932
933''Warning'': currently {{$db-row-obj}} is only implemented for Postgresql databases.
934
935
936<procedure>(sql-quote . data)</procedure>
937
938Escape and quote the concatenation of {{data}} to be used in SQL queries.
939
940''Warning'': for Sqlite databases, {{sql-quote}} just replaces {{'}} by {{''}} and quotes the {{data}}.  For Postgresql, {{sql-quote}} quotes the result of {{escape-string}}.
941
942
943
944==== Pages
945
946<procedure>(define-page path contents #!key css title doctype headers charset no-ajax use-ajax no-template no-session no-db no-javascript-compression)</procedure>
947
948Define an awful page.
949
950{{path}} is the path to the page.  It can be represented by two types: a string and a regular expression object.  If it is a string, the path used in the URI will be bound to the given no-argument procedure {{contents}}.  If it is a regular expression object, any request whose URL path matches the regular expression will br handled by the one-argument procedure {{contents}}.  This procedure will be given the requested path.
951
952The {{css}}, {{title}}, {{doctype}}, {{headers}} and {{charset}} keyword parameters have the same meaning as {{html-page}} (from the [[/egg/html-utils|html-utils]] egg).
953
954If {{no-ajax}} is {{#t}}, it means that the page won't use ajax, even if the {{enable-ajax}} parameter is {{#t}}.
955
956If {{use-ajax}} is {{#t}}, it means that the page will be linked to the ajax library, even if the {{enable-ajax}} parameter is {{#f}}.
957
958If {{no-template}} is {{#t}}, it means that no page template (see the {{page-template}} parameter) should be used.
959
960If {{no-session}} is {{#t}}, it means that the page should not use session.
961
962If {{no-db}} is {{#t}}, it means that the page should not use the database, even when database usage is activated by {{enable-db}} and {{db-credentials}} is not {{#f}}.
963
964If {{no-javascript-compression}} is {{#t}} the javascript code for the page is not compressed, even when {{enable-javascript-compression}} is not {{#f}}.
965
966Examples:
967
968<enscript highlight=scheme>
969
970(use srfi-1 ;; for filter-map
971     regex) ;; for regexp
972
973;; http://host:port/foo => "bar"
974(define-page "/foo"
975  (lambda ()
976    "bar"))
977
978;; http://host:port/add/1/2/3 => 6
979(define-page (regexp "/add/.*")
980  (lambda (path)
981    (let ((numbers (filter-map string->number (string-split path "/"))))
982      (number->string (apply + numbers)))))
983
984</enscript>
985
986
987<procedure>(define-session-page path contents . rest)</procedure>
988
989Define a session-aware page.  When the page is accessed and a correponding session does not exist, it is created.  If the session already exists and is not valid, it is recreated.  If the session already exists and is valid, then it is refreshed.
990
991The {{rest}} parameters are the same as for {{define-page}}.
992
993Here's an example (the [[http://www.paulgraham.com/arcchallenge.html|arc challenge]]):
994
995<enscript highlight=scheme>
996(use awful html-utils spiffy-request-vars)
997
998(define-session-page "said"
999  (lambda ()
1000    (with-request-vars* $ (said)
1001      (cond (said
1002             ($session-set! 'said said)
1003             (link "said" "click here"))
1004            (($session 'said)
1005             => (lambda (said)
1006                  (++ "You said: " said)))
1007            (else (form (++ (text-input 'said)
1008                            (submit-input))
1009                        action: "said"
1010                        method: 'post))))))
1011</enscript>
1012
1013
1014<procedure>(undefine-page path #!optional vhost-root-path)</procedure>
1015
1016Undefine a page whose path is {{path}} (a string or a regular expression object).
1017
1018The optional parameter {{vhost-root-path}} is the path of virtual host where the page is to be undefined.  If omited, {{(root-path)}} is used.
1019
1020
1021==== Ajax
1022
1023<procedure>(ajax path selector event proc #!key target (action 'html) (method 'POST) (arguments '()) success no-session no-db vhost-root-path live prelude update-targets)</procedure>
1024
1025Generate javascript code to be added to the page defined by {{define-page}}.  Return the generated javascript code (which usually is not useful, so should be discarded).
1026
1027{{path}} is the URL path (a string) of the server side handler. This path is placed under the {{(app-root-path)/(ajax-namespace)}} path.  So, if your {{app-root-path}} is {{"my-app"}}, your {{ajax-namespace}} is {{"ajax"}} and you use {{"do-something"}} as the first argument to {{ajax}}, the URL for the server side handler would be {{"/my-app/ajax/do-something"}}.
1028
1029{{selector}} is the selector for the DOM element to be observed.  If it is a quoted symbol, awful generates a JQuery selector by DOM id (e.g., {{'my-selector}} generates {{"#my-selector"}}).  If it is a string, awful uses it as-is to generate the JQuery selector (e.g., {{"input[name^=omg]"}} generates {{"input[name^=omg]"}}).
1030
1031{{event}} (a quoted symbol or a list) is the event(s) to be observed. If it is a quoted symbol (e.g., {{'click}}), only this event will be bound.  If {{event}} is a list of events, all the events from the list will be bound.
1032
1033{{proc}} is a no-argument procedure to be executed on the server side.
1034
1035The {{target}} keyword parameter is the id of the DOM element to be affected by the result of {{proc}}.
1036
1037The {{method}} (a quoted symbol, usually {{'GET}} or {{'POST}}) keyword parameter is the HTTP method to be used by the ajax request.
1038
1039The {{arguments}} keyword parameter is an alist mapping request variables (symbols) to their values (strings).  {{ajax}} uses these arguments to assembly the query string or the request body to send to the server when performing the ajax request.
1040
1041Example:
1042
1043<enscript highlight=scheme>
1044arguments: '((var1 . "$('#var1').val()")
1045             (var2 . "$('#var2').val()"))
1046</enscript>
1047
1048If the {{no-session}} keyword parameter is {{#t}}, it means that no session should be considered ({{ajax}} implicit sends the session identifier when {{no-session}} is {{#f}}).
1049
1050If the {{no-db}} keyword parameter is {{#t}}, it means that the should be no attempt to connect the database, even when database usage is activated by {{enable-db}} and {{db-credentials}} is not {{#f}}.
1051
1052The {{vhost-root-path}} keyword parameter (a string) is the vhost root path.  It is useful for explicitly separate pages defined using the same path (see {{define-page}}) but for different vhosts.
1053
1054The {{live}} keyword parameter (boolean) indicates wheter ajax should use JQuery's live method (see [[http://api.jquery.com/live/]]).
1055
1056The {{prelude}} keyword parameter (string) is an arbitrary piece of javascript code to be placed right before the ajax request.
1057
1058The {{update-targets}} keyword parameter a boolean indicating whether multiple targets should be updated upon ajax response.  When {{update-targets}} is used, the procedure {{proc}} used as argument to {{ajax}} should yield an alist as result.  The alist maps DOM elements identifiers to their corresponding values.
1059
1060Here's an example:
1061
1062<enscript highlight=scheme>
1063#!/usr/bin/awful
1064
1065(use awful html-tags)
1066
1067(enable-ajax #t)
1068
1069(define-page (main-page-path)
1070  (lambda ()
1071
1072    (ajax "foo" 'foo 'click
1073          (lambda ()
1074            '((a . 1) (b . 2) (c . 3)))
1075          update-targets: #t)
1076
1077    (<div>
1078     (link "#" "foo" id: "foo")
1079     (<div> id: "a")
1080     (<div> id: "b")
1081     (<div> id: "c"))))
1082</enscript>
1083
1084The {{success}} keyword parameter (string) can be any arbitrary javascript code to be executed on the successful ajax request.  The javascript code can assume that a variable {{response}} is bound and contains the request resulting data.  Here's an example:
1085
1086<enscript highlight=scheme>
1087#!/usr/bin/awful
1088
1089(use awful html-tags)
1090
1091(enable-ajax #t)
1092
1093(define-page (main-page-path)
1094  (lambda ()
1095
1096    (ajax "foo" 'foo "click"
1097          (lambda ()
1098            "hey")
1099          success: "$('#bar').html(response + ' you!')")
1100
1101    (++ (link "#" "foo" id: "foo")
1102        (<div> id: "bar"))))
1103</enscript>
1104
1105The {{ajax}} procedure is session, HTTP request and database -aware.
1106
1107
1108<procedure>(periodical-ajax path interval proc #!key target (action 'html) (method 'POST) (arguments '()) success no-session no-db vhost-root-path live prelude update-targets)</procedure>
1109
1110Periodically execute {{proc}} on the server side, using {{(app-root-path)/(ajax-namespace)/path}} as the URL path for the server side handler.
1111
1112{{interval}} (a number) is the interval between consecutive executions of {{proc}}, in milliseconds.
1113
1114The meaning of the keyword parameters is the same as for {{ajax}}'s.
1115
1116
1117<procedure>(ajax-link path id text proc #!key target (action 'html) (method 'POST) (arguments '()) success no-session no-db (event 'click) vhost-root-path live class hreflang type rel rev charset coords shape accesskey tabindex a-target prelude update-targets)</procedure>
1118
1119A shortcut to
1120
1121<enscript highlight=scheme>
1122(begin
1123  (ajax path id 'click proc ...)
1124  (<a> href: "#" [...other <a> keyword parameters...] id: id text))
1125</enscript>
1126
1127The meaning of the {{target}}, {{action}}, {{method}}, {{arguments}}, {{success}}, {{no-session}}, {{no-db}}, {{event}}, {{vhost-root-path}}, {{update-targets}} and {{live}} keyword parameters is the same as for {{ajax}}'s.
1128
1129The meaning of the {{class}}, {{hreflang}}, {{type}}, {{rel}}, {{rev}}, {{charset}}, {{coords}}, {{shape}}, {{accesskey}}, {{tabindex}} and {{a-target}} are the same as for [[/egg/html-tags|html-tags]]' {{<a>}} procedure (except that {{a-target}} is {{<a>}}'s {{target}}, since {{ajax}} uses the {{target}} keyword parameter).
1130
1131The {{event}} keyword parameter syntax is the same for {{ajax}}'s {{event}} mandatory parameter.
1132
1133
1134==== Redirection
1135
1136<procedure>(redirect-to uri)</procedure>
1137
1138Perform an HTTP redirection (code 302) to the given {{uri}} (either a string or a [[/eggref/4/uri-common|uri-common]] uri object).  To be used from {{define-page}} contents.  Example:
1139
1140<enscript highlight=scheme>
1141(use awful)
1142
1143;; / -> /foo
1144(define-page "/"
1145  (lambda ()
1146    (redirect-to "/foo")))
1147
1148(define-page "/foo"
1149  (lambda ()
1150    "foo"))
1151</enscript>
1152
1153The example above shows a redirection from {{/}} to {{/foo}}.  Redirections can also be performed when the origin path is a regular expression:
1154
1155<enscript highlight=scheme>
1156(use awful)
1157
1158;; /bar.* -> /foo
1159(define-page (regexp "/bar.*")
1160  (lambda (_)
1161    (redirect-to "/foo")))
1162
1163(define-page "/foo"
1164  (lambda ()
1165    "foo"))
1166</enscript>
1167
1168
1169==== Web REPL
1170
1171<procedure>(enable-web-repl path #!key css title)</procedure>
1172
1173Enable the web REPL.  {{path}} is the URL path to the web REPL.
1174
1175The keyword parameter {{css}} is the CSS to be used the the web REPL page (see the documentation for {{html-page}}, from the [[/egg/html-utils|html-utils]] egg, for the {{css}} keyword parameter.)
1176
1177The keyword parameter {{title}} (a string) is the title for the web REPL page (see the documentation for {{html-page}}, from the [[/egg/html-utils|html-utils]] egg, for the {{title}} keyword parameter.)
1178
1179The web REPL is automatically enabled by the awful application server when the {{--development-mode}} is provided (available from {{/web-repl}}).  By default, the fancy editor is used, but can be disabled with the {{--disable-web-repl-fancy-editor}} command line option for the awful application server.
1180
1181
1182==== Session inspector
1183
1184<procedure>(enable-session-inspector path #!key css title)</procedure>
1185
1186Enable the session inspector.  {{path}} is the URL path to the session inspector.
1187
1188The keyword parameter {{css}} is the CSS to be used the the session inspector page (see the documentation for {{html-page}}, from the [[/egg/html-utils|html-utils]] egg, for the {{css}} keyword parameter.)
1189
1190The keyword parameter {{title}} (a string) is the title for the session inspector page (see the documentation for {{html-page}}, from the [[/egg/html-utils|html-utils]] egg, for the {{title}} keyword parameter.)
1191
1192The session inspector is automatically enabled by the awful application server when the {{--development-mode}} is provided (available from {{/session-inspector}}).
1193
1194
1195=== Tips and tricks
1196
1197==== Use {{link}} and {{form}} for links and forms
1198
1199Instead of using {{<a>}} and {{<form>}} for creating links and forms, respectively, consider using the {{link}} and {{form}} procedures instead.  They are specially useful when using sessions, since they transparently handle the session identifier for you.  Even if you don't use sessions, they may save you some work if one day you decide to use sessions (then you won't have do to anything regarding to links and forms).
1200
1201
1202==== Use {{with-request-vars}} when referencing the same request variable multiple times
1203
1204When you need to access the same request variable more than once, consider using [[/egg/spiffy-request-vars|spiffy-request-vars]]' {{with-request-vars}}.
1205
1206For example, instead of:
1207
1208<enscript highlight=scheme>
1209(use awful)
1210
1211(define-page "save-and-show-user"
1212  (lambda ()
1213    ($session-set! 'user ($ 'user))
1214    (++ "Welcome " ($ 'user) "!")))
1215</enscript>
1216
1217consider using something like:
1218
1219<enscript highlight=scheme>
1220(use awful spiffy-request-vars)
1221
1222(define-page "save-and-show-user"
1223  (lambda ()
1224    (with-request-vars $ (user)
1225      ($session-set! 'user user)
1226      (++ "Welcome " user))))
1227</enscript>
1228
1229
1230==== Use the web REPL and the session inspector for debugging
1231
1232You can simply use the {{--development-mode}} option for the awful application server to enable the web REPL and the session inspector (when {{enable-session}} is {{#t}}).  The development mode allows access to them for the localhost.  When in development mode, the web REPL and the session inspector are available at the {{/web-repl}} and {{/session-inspector}} paths.
1233
1234If you want further flexibility, you can customize the web REPL and the session inspector.
1235
1236Here's a simple recipe to allow access for your local machine to the web REPL ({{/repl}}) and to the session inspector ({{/session-inspector}}).
1237
1238<enscript highlight=scheme>
1239(session-inspector-access-control
1240 (lambda ()
1241   (member (remote-address) '("127.0.0.1"))))
1242
1243(enable-session-inspector "/session-inspector")
1244
1245
1246(web-repl-access-control
1247 (lambda ()
1248   (member (remote-address) '("127.0.0.1"))))
1249
1250(enable-web-repl "/repl")
1251</enscript>
1252
1253To access them, just point your browser to {{http://localhost:<port>/repl}} and {{http://localhost:<port>/session-inspector}}, respectively.
1254
1255
1256==== Create custom page definers when {{page-template}} and/or plain {{define-page}} are not enough
1257
1258You can define your own page definers when {{page-template}} or the plain {{define-page}} is not enough for what you need.  Here's an example:
1259
1260<enscript highlight=scheme>
1261#!/usr/bin/awful
1262
1263(use awful html-tags)
1264
1265(define (define-custom-page path contents)
1266  (define-page path
1267    (lambda ()
1268      (<html> (<body> (contents))))
1269    no-template: #t))
1270
1271(define-custom-page (main-page-path)
1272  (lambda ()
1273    "Hey!"))
1274</enscript>
1275
1276If you access {{http://localhost:8080}} you'll get the following HTML code:
1277
1278  <html><body>Hey!</body></html>
1279
1280
1281==== Debugging: error messages on the browser window
1282
1283Error messages right on the browser window can be quite handy for debugging (although not for production environments).  Here's a way to accomplish that:
1284
1285<enscript highlight=scheme>
1286(use awful html-tags)
1287
1288(page-exception-message
1289 (lambda (exn)
1290   (<pre> convert-to-entities?: #t
1291          (with-output-to-string
1292            (lambda ()
1293              (print-call-chain)
1294              (print-error-message exn))))))
1295</enscript>
1296
1297This feature is automatically enabled when the awful application server is used with the {{--development-mode}} option.
1298
1299
1300
1301==== Run awful without arguments to quickly share a file
1302
1303When invoked without arguments, awful (the application) starts the web server using the current directory as root path and keeps listening on port 8080.  So, if you want to quickly share a file (or some files), change to the directory containing the files and execute {{awful}}.  The access {{http://<host>:8080/<the-file-you-want>}}.
1304
1305
1306
1307==== Awful badge
1308
1309Here's a suggestion:  [[image:http://parenteses.org/mario/img/thats-awful.png|That's awful!]]
1310
1311=== The name
1312
1313Awful doesn't mean anything special.  It's just awful.  But folks on freenode's #chicken (IRC) have suggested some acronym expansions:
1314
1315* A Whole Freaking Universe of Lambdas
1316* Authored Without Full Understanding of Logic
1317* Another Web Framework Understating Logic
1318* All Worthless Frameworks Unchain Laziness
1319* Armed With Flimsy Utility Lisp
1320* Awful Will Fed Up Lispers
1321* Awful Wildly Finalizes Unfinished Loops
1322* Another Widely Foolish Unknown Language
1323* Ain't Work For Unpleasant Laywers
1324* Aliens Would Find it Utterly Lame
1325* Aren't We Funny and Uncaring Lurkers
1326* Awful Will F*** Up Logic
1327* Awful Will Fart Upon Leaving
1328* Again Web Frameworks Underscore Lameness
1329* Attention While Fully Utilizing Laziness
1330* Another Webserver F***ing Up the Line
1331* Again We Forget Unclosed Lambdas
1332* All Web Features Understood Losslessly
1333* Anything With Fully Universal Lambdas
1334* Again We Fail Under Load
1335* Apocalyptic Warthogs Find Undiscovered Lands
1336* Accessible Web Framework Using Lisp
1337* Another Weird Framework Using Lisp
1338* All Waffles Fear Unicorn Landings
1339* A Working Facility Underscoring Laziness
1340* Another Webbot Flapping Under Lines
1341* Anybody Will Fake Unrealistic Loveletters
1342* Armadillos Would First Use Legs
1343* Astonishing Whales Fill Up Lakes
1344* Alternative Way to F*** Up Lisp
1345* Another Way to Find Undressed Ladies
1346* Amazing! Wonderful! Fantastic! Unbelievable! Lame.
1347* All Wonders Feel Useless Later
1348* Amazingly Wonderful Feeling, Using Lambdas
1349* Alligators Will Fear Us, Lunatics
1350* All Wussies Fear Ultimate Lambda
1351* Animals Will Find Us Letal
1352* Advanced Web Framework: Ultimate Lucubration
1353* Awful Will Feed Urban Lethargy
1354* Argument With Focus Upon Labelling
1355* Another Word Faking Unpremeditated Label
1356* Again We Find it Utterly Useless
1357* Ain't Work For Unattractive Ladies
1358* A Way For Using Lambdas
1359* Awful Way For Using Lambdas
1360* Apparently We Freaks Understand Lambdas
1361* Again We Foolishly Use Lists
1362* At Work Fools Use Lisp
1363* Again We Foolishly Use Lisp
1364* Another Wimp Fall Upon Lisp
1365* Accepting Whatever Fools Undertake Lightly
1366* Absurd Word For Unnatural Lingo
1367* Alternative Word For Useless Loser
1368* Acronym With Filled Up Letters
1369* Acronym We Find Utterly Lame
1370* Another Webserver Functioning Until Launched
1371* Applications With Familiar, Understandable Language
1372* (Awful Words Forming Useless List)
1373* All Who Force Unusual Layout
1374* Again We Fear Undescribable Lamenting
1375* Awful Will Favour Ugly Layouts
1376* Apes With Frequent Uncontrolled Lunacy
1377
1378==== Acknowledgements (IRC nicknames on freenode's #chicken):
1379
1380
1381* C-Keen
1382* DerGuteMoritz
1383* elderK
1384* elf
1385* florz
1386* merlincorey
1387* sjamaan
1388
1389=== FAQ (aka Fakely Asked Questions)
1390
1391==== How does awful bind URIs to files/directories on the filesystem and procedures?
1392
1393Explanation by example:
1394
1395When a procedure is bound to a path {{a}} (like {{(define-page "a" (lambda ...))}}) and the request is made to {{a/}}, the awful behavior is the following:
1396
1397* if the path {{a}} does not exist, the server replies with the result of the evaluation of the procedure bound to {{a}}.
1398
1399* if {{a}} is an existent file, the server replies with the file contents (or the result of processing the file, in case it is a special one like [[/egg/spiffy#web-scheme-handler|web-scheme]] or {{.ssp}} files)
1400
1401* if {{a}} is an existing directory and the directory contains one of the files in {{index-file}} (see documentation for [[/egg/spiffy|Spiffy]]), with the index file contents (or the result of processing the file, in case it is a special one like [[/egg/spiffy#web-scheme-handler|web-scheme]]'s or {{.ssp}})
1402
1403* if {{a}} is an existing directory and does not contain index files, the server replies with the result of the evaluation of the  procedure bound to {{a}}.
1404
1405
1406=== Known bugs and limitations
1407
1408* The {{ajax}} procedure is not session-aware when called from {{define-session-page}} (it is when called from {{define-page}}) and cookies are not enabled (i.e., {{enable-session-cookie}} is {{#f}}).  To workaround this bug, you can explicitly pass the sid (see the read-only {{sid}} parameter) along with requests (see the {{arguments}} keyword parameter for {{ajax}} and ajax-related procedures).
1409
1410* Awful currently doesn't detect if cookies are enabled on the client side.
1411
1412
1413
1414=== License
1415
1416BSD
1417
1418
1419=== Version history
1420; 0.27: Require the {{regex}} egg, for chickens >= 4.6.2
1421
1422; 0.26:
1423* {{define-page}} allows page redefinitions
1424* Added the {{undefine-page}} procedure
1425* Fancy web REPL (enabled by default).  The awful application server now accepts the {{--disable-web-repl-fancy-editor}} command line option to disable the web REPL fancy editor.
1426* Added the following parameters, related to the fancy web REPL: {{enable-web-repl-fancy-editor}} and {{web-repl-fancy-editor-base-uri}}.
1427* Bug fix for the development mode: requests to the {{/reload}} path killed {{/web-repl}} and {{/session-inspector}}
1428
1429; 0.25:
1430* The awful application server can now be used with the {{--development-mode}} command line option, which enables the web REPL, the session inspector (when {{enable-session}} is #t) for the localhost and on-browser error messages and backtraces.  When running in development mode, the {{/reload}} path is defined to reload awful apps.
1431* The awful application server now supports the {{--ip-address}} and {{--port}} command line options.
1432* {{use-ajax}} keyword parameter for {{define-page}} (for when {{enable-ajax}} is {{#f}} and you need ajax for some specific pages only)
1433* Added {{awful-response-headers}} and {{development-mode?}} parameters
1434
1435; 0.24:
1436* initial support for storing session identifiers in cookies.  Added the {{enable-session-cookie}} and {{session-cookie-name}} parameters.  By default, cookies-sessions are enabled (relevant only when using sessions, of course). '''Warning''': if your code relies on the availability of session identifiers in the query string or in the request body for whatever reason, it will break.
1437* initial support for HTTP redirection via {{redirect-to}}.
1438* web-repl and session-inspector beautification
1439* web-repl and session inspector provide a {{headers}} keyword parameter
1440* fixes for {{define-page}} regarding to regex-based paths
1441* {{ajax}} always prioritizes the {{success}} keyword parameter value (when it's given) to generate code for JQuery's {{success}} attribute, even when {{target}} and {{update-targets}} are given
1442* awful (the application) handles the {{-v}} and {{--version}} command line options
1443
1444; 0.23:
1445* added the {{update-targets}} keyword parameter for {{ajax}}, {{periodical-ajax}} and {{ajax-link}} procedures (multiple targets update support)
1446* added the {{debug-resources}} parameter for debugging the resources table
1447* the {{js}} keyword parameter for {{ajax}}, {{periodical-ajax}} and {{ajax-link}} has been renamed to {{success}} (to match JQuery's API naming for Ajax). '''Warning''': if your code uses the {{js}} keyword parameter for {{ajax}}, {{periodical-ajax}} or {{ajax-link}}, this change will break your code.
1448* the javascript variable bound to the response data on successful ajax request has been renamed to {{response}} (it was {{h}} before). The same warning for the {{js}}->{{success}} renaming is valid for this change, since it is directly related to {{js}} (now {{success}}).
1449* the default value for {{main-page-path}} is now {{"/"}} (it was {{"/main"}} before).  There's no more main page redirection.  '''Warning''': if your code relies on hardcoded {{"/main"}} paths (instead of using {{(main-page-path)}}) or if you rely on the main page automatic redirection, this change will break your code.
1450* {{ajax}} bugfix regarding to session identifiers (could cause "Invalid session ID" errors in some cases, specially with {{define-session-page}}).
1451* better handling of URI paths regarding to paths as directories (see FAQ's ''How does awful bind URIs to files/directories on the filesystem and procedures?'')
1452
1453; 0.22:
1454* bug fix: fixed unintended shadowing of {{js}} in ajax
1455* added the {{prelude}} keyword parameter for {{ajax}}, {{periodical-ajax}} and {{ajax-link}}
1456* {{$db}} supports the {{values}} keyword parameter (patch by Stephen Eilert)
1457* awful (the application) can now be invoked without arguments
1458* awful (the application) handles {{-h}} and {{--help}}
1459* dropped [[/eggref/4/jsmin|jsmin]] requirement
1460
1461; 0.21: ajax and main page redirection issues fixes
1462
1463; 0.20:
1464* {{page-access-control}} controls access to pages even when no session is in use
1465* '''Warning''': the following parameters have been removed: {{enable-reload}}, {{reload-path}} and {{reload-message}}.  Now the way to define reloaders is via {{define-page}}.
1466* new parameter: {{awful-apps}} (a list of awful applications as passed to the awful server)
1467
1468; 0.19: bug fix for {{(reload-path)}} handler
1469
1470; 0.18:
1471* support for regex-based page paths (see {{define-page}})
1472* {{define-page}} checks whether the second arg is a procedure.
1473* use {{-O3 -lambda-lift}} instead of {{-O2}} for compilation
1474* {{main-page-path}} redirection made with code stolen from [[/egg/spiffy|spiffy]]'s {{send-response}}
1475
1476; 0.17 : .meta bug fix.  postgresql is not required as a dependency (thanks to Stephen Pedrosa Eilert for pointing this issue).
1477; 0.16 :
1478* added {{define-session-page}}
1479* bug fix for {{link}}
1480
1481; 0.15 : jquery updated to 1.4.2 ({{ajax-library}}).
1482; 0.14 : {{link}}'s {{args}} keyword parameter renamed to {{arguments}} (the same as {{ajax}}'s).
1483; 0.13 : Session-aware {{link}} and {{form}} procedures.  Bug fix for {{ajax-link}} (was not passing the {{class}} keyword argument to <a>).
1484; 0.12 : Containers for user and password fields ({{login-form}})
1485; 0.11 : awful sets Spiffy's {{root-path}} to {{(current-directory)}}
1486; 0.10 :
1487* Multiple database support. Currently Postgresql (via [[/egg/postgresql|postgresql]] egg) and Sqlite3 (via [[/egg/sqlite3|sqlite3]] and [[/egg/sql-de-lite|sql-de-lite]] eggs) are supported.  See [[/egg/awful-postgresql|awful-postgresql]], [[/egg/sqlite3|sqlite3]] and [[/egg/sql-de-lite|sql-de-lite]] eggs.
1488
1489* Removed requirement for postgresql
1490
1491* {{enable-db}} is now a procedure (not a parameter as before) and accepts no arguments
1492
1493; 0.9 : {{login-form}} gets the {{user}} refilled when the session or passowrd is not valid.  This feature may be disabled by setting the {{refill-user}} keyword parameter for {{login-form}} to {{#f}} (default is {{#t}}).  Thanks to Arthur Maciel for suggesting this feature.
1494; 0.8 :
1495* jquery updated to 1.4.1 ({{ajax-library}}).
1496
1497* support for jquery's {{live}} method ({{live}} keyword parameter for {{ajax}}, {{ajax-link}} and {{periodical-ajax}}).  See [[http://api.jquery.com/live/]]
1498
1499* bug fixes: {{periodical-ajax}} and {{ajax-link}} propagate {{vhost-root-path}} to {{ajax}}
1500
1501* added {{awful-start}} and dropped spiffy requirement for awful (the server)
1502
1503* dropped requirement for miscmacros
1504
1505* added more ajax tests
1506
1507; 0.7 : {{ajax-link}} accepts all {{<a>}}'s keyword arguments
1508; 0.6 : Explicitly depends on [[/egg/http-session|http-session]] 2.0
1509; 0.5 : Reload handler register the reload path after reloading.
1510; 0.4 : {{disable-reload?}} renamed to {{enable-reload}}.  {{enable-reload}} is {{#f}} by default.
1511; 0.3 : {{awful}} (the server) allows applications to use Chicken syntax ({{use}}, {{include}} etc)
1512; 0.2 : Added javascript compression support
1513; 0.1 : Initial release
Note: See TracBrowser for help on using the repository browser.