2.11 Templates
On this page:
2.11.1 Static
2.11.2 Dynamic
2.11.3 Gotchas
2.11.4 HTTP Responses
2.11.5 API Details
include-template
in
Version: 4.1.3

2.11 Templates

 (require web-server/templates)

The Web Server provides a powerful Web template system for separating the presentation logic of a Web application and enabling non-programmers to contribute to PLT-based Web applications.

    2.11.1 Static

    2.11.2 Dynamic

    2.11.3 Gotchas

    2.11.4 HTTP Responses

    2.11.5 API Details

2.11.1 Static

Suppose we have a file "static.html" with the contents:

  <html>
   <head><title>Fastest Templates in the West!</title></head>
   <body>
    <h1>Bang!</h1>
    <h2>Bang!</h2>
   </body>
  </html>

If we write the following in our code:

  (include-template "static.html")

Then the contents of "static.html" will be read at compile time and compiled into a Scheme program that returns the contents of "static.html" as a string:

  "<html>\n  <head><title>Fastest Templates in the West!</title></head>\n  <body>\n    <h1>Bang!</h1>\n    <h2>Bang!</h2>\n  </body>\n</html>"

2.11.2 Dynamic

include-template gives the template access to the complete lexical context of the including program. This context can be accessed via the @-Reader syntax. For example, if "simple.html" contains:

  <html>
   <head><title>Fastest @thing in the West!</title></head>
   <body>
    <h1>Bang!</h1>
    <h2>Bang!</h2>
   </body>
  </html>

Then

  (let ([thing "Templates"])
    (include-template "simple.html"))

evaluates to the same content as the static example.

There is no constraints on the values, the way they are used, or the way they are defined, that are made accessible to the template. For example,

  (define (fast-template thing)
    (include-template "simple.html"))
  
  (fast-template "Templates")
  (fast-template "Noodles")

evalutes to two strings with the predictable contents:

  <html>
   <head><title>Fastest Templates in the West!</title></head>
   <body>
    <h1>Bang!</h1>
    <h2>Bang!</h2>
   </body>
  </html>

and

  <html>
   <head><title>Fastest Noodles in the West!</title></head>
   <body>
    <h1>Bang!</h1>
    <h2>Bang!</h2>
   </body>
  </html>

2.11.3 Gotchas

One of the most important things to remember about the @-Reader syntax is that the @ symbol must be escaped in content:

  <html>
   <head><title>Fastest @"@"s in the West!</title></head>
   <body>
    <h1>Bang!</h1>
    <h2>Bang!</h2>
   </body>
  </html>

The other gotcha is that since the template is compiled into a Scheme program, only its results will be printed. For example, suppose we have the template:

  <table>
   @for[([c clients])]{
    <tr><td>@(car c), @(cdr c)</td></tr>
   }
  </table>

If this is included in a lexical context with clients bound to (list (cons "Young" "Brigham") (cons "Smith" "Joseph")), then the template will be printed as:

  <table>
  </table>

because for does not return the value of the body. Suppose that we change the template to use for/list (which combines them into a list):

  <table>
   @for/list[([c clients])]{
    <tr><td>@(car c), @(cdr c)</td></tr>
   }
  </table>

Now the result is:

  <table>
   </tr>
   </tr>
  </table>

because only the final expression of the body of the for/list is included in the result. We can capture all the sub-expressions by using list in the body:

  <table>
   @for/list[([c clients])]{
    @list{
     <tr><td>@(car c), @(cdr c)</td></tr>
    }
   }
  </table>

Now the result is:

  <table>
   <tr><td>Young, Brigham</td></tr>
   <tr><td>Smith, Joseph</td></tr>
  </table>

The templating library provides a syntactic form to deal with this issue for you called in:

  <table>
   @in[c clients]{
    <tr><td>@(car c), @(cdr c)</td></tr>
   }
  </table>

Notice how it also avoids the absurd amount of punctuation on line two.

2.11.4 HTTP Responses

The quickest way to generate an HTTP response from a template is using the list response type:

  (list #"text/html" (include-template "static.html"))

If you want more control then you can generate a response/full struct:

  (make-response/full
   200 "Okay"
   (current-seconds) TEXT/HTML-MIME-TYPE
   empty
   (list (include-template "static.html")))

Finally, if you want to include the contents of a template inside a larger X-expression :

  `(html ,(include-template "static.html"))

will result in the literal string being included (and entity-escaped). If you actually want the template to be unescaped, then create a cdata structure:

  `(html ,(make-cdata #f #f (include-template "static.html")))

2.11.5 API Details

(include-template path)

Compiles the template at path using the @-Reader syntax within the enclosing lexical context.

Example:

  (include-template "static.html")

(in x xs e ...)

Expands into

  (for/list ([x xs])
   (list e ...))

Template Example:

  @in[c clients]{
   <tr><td>@(car c), @(cdr c)</td></tr>
  }

Scheme Example:

  (in c clients "<tr><td>" (car c) ", " (cdr c) "</td></tr>")