The simplicity of Sinatra brought to Tcl.
package require Toolatra
get / {
show "Good morning!"
}
runToolatra is a micro web framework that is very similar to Sinatra, but is ported to Tcl.
-
Sinatra-like syntax
-
A module that provides a fully-featured template engine
-
Built-in web server that integrates easily with Nginx or Apache
-
A module for generating and validating authorization tokens
Handling a GET request to a specific path:
package require Toolatra
get / {
show {Hello there, stranger!}
}
runIf you save and run this file with tclsh and then go to http://127.0.0.1:5050, you should see Hello there, stranger!.
SPOILER! Specifying the port number on which the server should be ran to the run command will start Toolatra’s server on that port.
Throwing HTTP errors:
package require Toolatra
get /this-will-cause-an-error {
error 404
}
runBy default, Toolatra’s ugly error handler will be used. To replace it with a custom one, just define a GET request handler with the path set to /<HTML error code here>. Example:
package require Toolatra
get /404 {
show "Whoops, an error has occured."
}
get /this-will-cause-an-error {
error 404
}
runServing additional headers:
package require Toolatra
get / {
header Content-type text/plain
show {Look, I'm plain text!}
}
runUsing templates:
package require Toolatra
package require ToolatraTemplates
get / {
etcl index.html [dict create name Tim]
}
runExample contents of index.html (it must be located in templates folder):
<h1>Hello there, @name@!</h1>
<p>Did you know that I can run Tcl code from here? Just look: 2 + 2 = @expr {2+2}@</p>Speaking of templates, you don’t have to use Toolatra’s template engine - you can use Mustache templates if you want in a pretty similar manner (you’ll need ianka’s mustache.tcl library installed first, though);
package require Toolatra 19.12
package require ToolatraMustache 20.06 ;# needed for Mustache templates to work
get / {
mustache greeter.html [dict create name Tim]
}Example contents of greeter.html.mustache located inside the templates folder:
<h1>Hello again, {{name}}!</h1>Serving dynamically-generated binary data:
package require Toolatra 19.12
get / {
set binDtDesc [open a.out r]
fconfigure $binDtDesc -translation binary -encoding binary
set ctnt [read $binDtDesc]
close $binDtDesc
bshow $ctnt application/octet-stream ;# or brender
}Accessing query string parameters:
package require Toolatra
package require ToolatraTemplates
get / {
if {[dict exists $params name]} {
show "Hello, [dict get $params name]!"
} else {
etcl form.html
}
}
runform.html template:
<form method=GET action=/>
<p>Your name: <input type="text" name=name /></p> <button type=submit>Greet me!</button>
</form>This Tcl wiki page contains some useful examples on using templates and layouts: https://wiki.tcl-lang.org/page/Toolatra
Accessing header values:
package require Toolatra
get / {
if {[dict exists $params User-Agent]} {
show [dict get $params User-Agent]
} else {
show None
}
}
runRedirecting to other pages:
package require Toolatra
get / {
redirect http://example.com
}
runHandling POST requests with data:
package require Toolatra
post / {
render "Data sent: $rawData"
}
get / {
render "Params/headers sent: $params"
}
runHandling cookies:
package require Toolatra 19.12
get / {
if {[cookie token] != {}} {
show "Cookie 'token' is set to [cookie token]"
} else {
redirect /settoken
}
}
get /settoken {
cookie token [expr {int(rand() * 9999)}]
}Authorization example:
set toolatra_auth ",(!%" ;# this is a 4-digit string that will be used to later encode the tokens that ToolatraAuth produces
package require Toolatra 19.12
package require ToolatraTemplates 19.11
package require ToolatraAuth 19.12
get / {
set cv [cookie authToken]
if {! [tokenValid $cv]} {
redirect /login
} else {
redirect /greet
}
}
get /login {
if {! [dict exists $params nm]} {
etcl form.html
} else {
set name [dict get $params nm]
set tkn [token $name] ;# the generated token will expire in 1 day, to specify the expiration date, specify the number of seconds as the second argument
cookie authToken $tkn
redirect /greet
}
}
get /greet {
set tkn [cookie authToken]
if {! [tokenValid $tkn]} {
redirect /login
} else {
set name [tokenValue $tkn]
show "Greetings, $name!"
}
}
runwhere form.html is:
<form>
<p>To continue, please enter your name.</p>
<p>Name: <input type=text name=nm /></p>
<button type=submit>Next</button>
</form>