jimhttp

What jimhttp
Where https://github.com/dbohdan/jimhttp
Description A collection of largely independent libraries for Jim Tcl and Tcl 8.x and a Sinatra and Flask -style web microframework for Jim Tcl. The microframework provides a rough implementation of the HTTP protocol and routing. The libraries implement document templates, an HTML DSL, persistent storage powered by SQLite3, a Redis client, and other features. The most popular component of jimhttp is a pure Tcl JSON serializer and parser that supports schemas.
Platforms Likely all supported by Jim Tcl's aio .
Prerequisites The web framework itself requires Jim Tcl 0.76 or later. Half of the components works in both Jim Tcl 0.76+ and Tcl 8.5+.
Updated 2024-03-29
License MIT
Contact dbohdan

Components

See https://github.com/dbohdan/jimhttp#components for what is included.

Code examples

http.tcl

source http.tcl

::http::add-handler GET /hello/:name/:town {
    ::http::respond [::http::make-response \
            "Hello, $routeVars(name) from $routeVars(town)!"]
}

::http::start-server 127.0.0.1 8080

json.tcl

# This produces the output
# {"a": "123", "b": 123, "c": [123, 456], "d": "true", "e": true}
source json.tcl

puts [::json::stringify {
    a 123
    b 123
    c {123 456}
    d true
    e true
} 0 {
    a string
    c {N* number}
    d string
}]

Discussion

ekd123 - 2014-09-30 08:04:39

Will there be a "tclhttp" written in Tcl?

dbohdan 2014-09-30: It's not a goal for me for now (especially since there are already web frameworks for Tcl) but I would welcome a compatibility patch that makes the code work in both. Porting should be pretty straightforward except for the use of static variables (though static variables can be emulated with namespaces, e.g, by mapping variable varName to $procName::$varName).

aspect 2014-10-01: I just spent an hour or so trying to shim this to run under Tcl (as a Jim learning exercise - nothing more), and while I didn't succeed it certainly looks feasible. A jimshim package would have to do a couple of things:

  • shim set and proc to create the namespace if it doesn't already exist
  • simulate statics as dbohdan describes above
  • extend proc to support TIP#288+ styled arglists, with optional args in the middle. I have a package which approaches this, if anyone's interested.
  • qualify namespaces appropriately -- namespaces in jimhttp aren't explicitly rooted in ::, though it looks like that's how they function
  • do array<->dict binding a la tie to support jim's dict(subscript) notation
  • do a little bit of magic to support the pattern global ns::x; set ns::x. The relative qualified names may make it tricky
  • provide a compatibility wrapper around sqlite3 - just sqlite3.open and the query method are sufficient for jimhttp
  • provide a compatibility wrapper around socket -server
  • provide a stdout command which is almost exactly an alias to fconfigure stdout.

That might be all that's needed. Some (all?) of these are quite trivial edits to the code as it is, but a shim to run it unmodified would be quite nice. Appropriate wrappers for socket and sqlite3 should be trivial in TclOO. If anyone's motivated enough to make a page for Jim Shim and start building a package, I'm happy to contribute what I have so far ... though I have no direct use for it right now, and no real experience with Jim, so quality and support from my end should not be relied upon ;-).

Worth noting: several of jimhttp's modules run perfectly on Tcl without modification. It might be more fun to pull those out and use them with Wibble or Woof! or Rivet or Wub or H . I think that's all the most popular Tcl HTTP stacks today?

dbohdan 2014-10-02: Interesting! I like the idea of a Jim compatibility shim. It could even be a starting point for something like Python's six ; six is a Python package that, when imported, provides the same standard library API in Python versions 2.x and 3.x, which by themselves have incompatibilities. Obviously, something like that would be a larger undertaking and harder to implement. As a bonus it could, e.g, help establish a dominant format for statics in Tcl (I am not aware of one). I can not work on such a compatibility project myself right, so if anyone else wants to the idea is up for grabs. :-) For now I have made plans to look into writing a shim based on your analysis that provides just the functionality that jimhttp uses with minimal changes to jimhttp itself.

I pushed a update today that roots all namespaces used in jimhttp in the global namespace. It doesn't matter for Jim but should make Tcl compatibility easier and there was really no reason not to (except maybe slightly uglier-looking code because of all the double colons). As for socket -server, I have a wrapper from an earlier project parts of which became the basis for jimhttp:

if {[catch {info tclversion}]} {
    set interpreter Jim
} else {
    set interpreter Tcl
    package require struct
    interp alias {} lmap {} struct::list mapfor
}
puts "Running in $interpreter."

# [...]

proc start-server {ipAddr port} {
    global interpreter

    if {$interpreter eq "Tcl"} {
        proc accept {channel clientaddr clientport} {
            chan event $channel readable [
                list serve $channel $clientaddr $clientport
            ]
        }
        socket -server accept -myaddr $ipAddr $port
    } else {
        global s
        set s [socket stream.server $ipAddr:$port]
        $s readable {
            set client [$s accept addr]
            serve $client {*}[split $addr :]
        }
    }
    vwait done
}

json.tcl, html.tcl and template.tcl work in Tcl 8.5 if you create the namespace beforehand with something like proc source-x filename { namespace eval file rootname $filename {}; source $filename }; source-x html.tcl;. You may find json.tcl interesting for implementing both decoding and encoding JSON arrays as number-keyed dictionaries as suggested in https://core.tcl-lang.org/tcllib/tktview?name=2967134fff . You'll also need a + proc for json.tcl.

Thanks for pointing out H to me; I didn't know about it. The question of popular Tcl HTTP stacks (or more narrowly, web application frameworks) is something I started researching recently. Unfortunately, I couldn't find any up-to-date comparison of them. So far I've made the wiki page web framework that I hope might fulfill this role in the future and have filled in some details; however, nothing can replace actual experience with the stacks themselves. While there is overlap here with the HTTP server category the scope of a modern web application framework is^W makes it its own distinct thing with some functionality expected that wouldn't necessarily be in a "normal" web server.

aspect: The web framework page is timely. H is Colin's recent effort to strip down Wub to essentials, as apparently some folks (myself included) found the whole package a bit much to digest. As you'll see from the examples, it's very easy to use, though some of the modules still need a bit of de-Wubification. There's been quite a bit of activity on the Tcl'ers chat of late with folks using these frameworks for websites and HTTP services - I'd recommend asking on there if you want to learn more. Alternatively, chatters are likely to see this activity in recent changes and pipe in with more detail :-).

dbohdan 2014-10-03: I'd be glad to see others chime in. To make the most of their contributions we'll probably need to improve the "schema" of that table. The formatless "description" column makes contributing facts that could help differentiate the frameworks harder than it should be.

See also