Instead of setting the http response body from a simple string, we can use templates to build parameterised content. Here's a simple program to serve some sample data from a template:
import("http")
route := {method:str path:str, relgen:str}{
["", "/", "index_handler"]
}
index_handler := {
method:str, path:str,
response:tuple{header:{k:str, seq:int, v:str}, status:int, body:str},
} begin
response := http.response{*,
body:=execute_template("b1", "hello1", tuple{mydata:=S})
}
yield
end
main := {} begin
template_register(batch_name:="b1", template:=dee(
template_name:="hello1",
template_content:=
"<!doctype html><title>Hello</title><h1>Data Server</h1><pre>{{ . }}</pre>"
))
res := http.serve(route:=route)
print(res)
end
As before, it imports the http module, defines a route
and the main function is set to start the server using the http.serve
relation generator.
This time, the main function also registers a template for later use in the handler. The template_register
function can be given a number of templates to build a "batch". Each template is given a name and some content which can be any text with optional parameters in between {{
and }}
bracket-pairs. Here we've used .
which indicates the top-level (root) parameter, which we'll pass in via the execute_template
call in the index_handler.
Our handler, index_handler
, sets the response body from the execute_template
call. It needs the batch_name and a template_name, matching ones registered earlier, and then a tuple containing the data to be used as the root for any template parameters. The tuple can be accessed within the template as {{ . }}
. The attributes within the tuple can be referenced then by name, e.g. {{ .mydata }}
would get the mydata
value, i.e. S
.
In a browser, hitting http://localhost:8080 would give:
Data Server
┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ mydata ┌─────┬───────┬────────┬────────┐ │ SNO │ SNAME │ STATUS │ CITY │ ├═════┼───────┼────────┼────────┤ │ S1 │ Smith │ 20 │ London │ │ S2 │ Jones │ 10 │ Paris │ │ S3 │ Blake │ 30 │ Paris │ │ S4 │ Clark │ 20 │ London │ │ S5 │ Adams │ 30 │ Athens │ └─────┴───────┴────────┴────────┘ ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
Some things to note about the template content:
- We now have a valid HTML page, albeit very minimal. We pass the <!doctype html> tag and so have the ability to return links to stylesheets and scripts etc.
- Later we can move the template contents into separate files to make it easier to edit them, share common chunks, and check them for matching tags and syntax errors etc.
Some things to note about the template data:
- The
mydata
passes a relvar which has no left-to-right attribute order nor a top-to-bottom tuple order. Therefore in theory, each time the data is requested it could appear in different orders each time. We'll see later how to prevent this by passing an array of tuples instead, and show ways to control the left-to-right ordering. - The
{{ . }}
effectively inserts a textual representation of the parameter, in this case a tuple containing a relation. While this works, we can do much better by rendering an HTML representation using therender
function.
Next we'll see how we can render data in a format more suitable for HTML.