Web application frameworks (was: [Haskell] Re: Trying On Learn Haskell Web Server)

[Switching to haskell-cafe] Niklas Broberg wrote:
Ehum, shameless plug. :)
Pretty much what I was fishing for...
On 3/6/06, Graham Klyne
wrote: Ah, neat, I knew about WASH, but somehow I'd missed the fact that there was a server there :) Interesting... at a casual glance, this looks as if it could be coming close to being a "full stack web application framework" for Haskell, looking to occupy
Cale Gibbard wrote: the same kind of territory as systems like Java/Servlets+JSP+the rest, Ruby/Rails or Python/Turbogears (the last a package I'm currently using).
Have you looked at HSP [1]? This is exactly what the HSP project aims for, although there is quite some ways to go yet.
I've noticed it, but haven't yet taken a closer look. Currently, I'm pretty busy with non-Haskell activities, but I'd love to find a sufficiently mature tool to migrate some of my work to Haskell.
I think see: The web server CGI process dispatching Web page templating Relational database access
All of these are present in HSP.
I noticed that WASH makes some mention of HSP. My main concern with a *SP approach, and a reason I haven't delved more deeply, is that they are, AFAICT, heavily dependent on code embedded in HTML, when I really want to separate the code and markup as much as possible.
Additional features of a full-stack web application framework that may or may not be present are:
- Support for longer-running web processes (implemented in haskell, of course)
HSP has that.
Ah, OK... I wasn't aware of that.
- An easy way to map incoming URIs to specific functions (hmm.. or to monadic values, I think)
I don't think I understand what you're after exactly, but I'm sure it's interesting, care to explain a bit further? :-)
I'll try and explain using Turbogears as example. Actually, I think that Turbogears would make a good model for building a Haskell Web application framework, since many of the key integration points are implemented using higher order functions. It makes heavy use of Python 2.4 "decorators", which are a (constrained) form of functional composition for class member functions. The web server/controller component of Turbogears is CherryPy. Roughly, a class maps to a web server "directory" in URI space, with a declared class (conventionally "root") corresponding to path / for a server. Member variables use used to create subdirectories. here's an example from soemthign I'm working on: [[ class Root(controllers.Root): panel = PanelRenderer() ### Note 1 webbrick = WebBrickAccess() itunes = ITunesAccess() @turbogears.expose(html="templates.welcome") ### Note 2 def index(self): return dict(now=time.ctime()) @turbogears.expose(html="templates.listpanels") ### Note 2 def panels(self): def selectPanelName((_,nam)): return nam[:-4] pattern = re.compile( r'^.+\.xml$' ) c = CollectFiles("../resources/paneldef/",pattern,recursive=False) return { 'baseuri' : turbogears.url("/")+"panel/", ### Note 3 'panels' : map(selectPanelName,c) } ]] Notes: 1. These assignments create sub-pages of the root page for http://.../panel/, http://.../webbrick/, http://.../itunes/. 2. This is the Python decorator syntax, that defines a class method as a composition of the decorator function (turbogears.expose) and the function definition that follows. The turbogears.expose decorator performs two functions here: (a) it causes the function to be exposed as a web page; e.g. http://.../index or http://.../panels, (b) it uses the output from the defined function as input to a templating system to format and return an HTML web page. 3. The templating system uses a Python "dictionary" type to accept values that are included in the constructed web page. You will note that this code is completely independent of the details of the templating syst actually used. Indeed, Turbogears can be used with more than one templating system, and (in principle), I think the decorator system would allow miore than one such system to be used within a single application - not that I advocate this ;). I think all of this could be converted quite easily to appropriate Haskell idioms.
- Easy mapping from Haskell data structures to underlying SQL - what would be called an Object-Relational Mapper (ORM) in OO languages
Some of our students are working on bringing the power of Ruby/Rails to HSP, with emphasis on smooth database interfacing. Not sure exactly what this entails though, I've never used Rails... :-)
IMO, Rails suffers in this respect by being too-tightly integrated with its ORM system. It's fine if you want, as Bruce Tate says, to "babysit a relational database". By in my application, I actually want to "babysit" a collection of web-connected devices. Turbogears, by contrast, leaves the controller/model interface completely in the open: there is no presumtpion that the supplied ORM code will be used. This means I can simply call my own (web client library) code instead of the ORM code, and everything just works. With rails, on brief examination, I felt that IK wpould need to unpick the ORM interface and then implement my own "model" code behind that interface -- just the kind of complexification and dependency I'm trying to get away from.
- Handling of interaction with a browser-side Javascript library for smoother AJAX support
This is not currently present in HSP, but they are surely on the conceptual todo-list. There is a design for a crude JavaScript support, but we'd certainly need more.
In turbogears, this mostly amounts to validation of form results coming back from Ajax-enabled forms, as far as I can tell. It's not a feature I've used yet. BTW, the Mochikit Ajax library (component of Turbogears) is an interesting example of functional idioms used in Javascript.
- Options to run the whole thing behind Apache to leverage its security and web space management capabilities
Lemmih has implemented a HSP/FastCGI binding for Apache. I also know that work is being done on building a direct HSP/Apache binding. All work in progress though.
Yes, I was aware of a fastCGI for Haskell. Didn't Bjorn Bringert (also) implement one? I tend to think of CGI programs as run-to-completion-then-exit, even when a fastCGI interface allows a persistent wrapper program to speed startup. But I could easily be missing something here.
I think that continuation-based web session state management, ala Smalltalk/Seaside, would be a very natural fit for a Haskell framework -- all handled by a "Web session monad", maybe. (Or maybe I just don't know what I'm talking about ;)
This is by far the biggest drawback of HSP today. There is no high-level support for continuations (other than explicitly defined continuations at top level).
This is something that I assume would not necessarily be (too) tightly integrated into the rest of the framework. This is only a very vague sketch, and I might be talking rubbish as I haven't studied this are in any depth, but I imagine using something a monad to maintain the state of a web session, with each incoming request corresponding to a bind operation, updating the session state and returning a value to the client. I'm not sure how closely this follows technically the idea of using continuations, but I think the end result is similar: cleaner and well-isolated management of session state and web transaction progress.
How far are we from having such a framework for Haskell?
Depends on how many people would be willing to invest time in it. Right now we have students at Chalmers working on a project that aims towards such a framework, but they can only do so much in the time they have. We would surely welcome any help we could get. :-)
Well, it's the sort of project I'd love to work on, but right now I also lack time. I've felt for a long time that Haskell would be a great language for building Web applications, and my work with Turbogears is showing me how it might actually all come together. Part of the problem is finding someone who is prepared to sponsor such work, as I've already taken a year or so working on my own projects, and not ready to take the financial hit again.
(ps. Going on vacation for 2 weeks in a few hours, so I'm not likely to respond for a while... ;-))
Have fun! #g -- PS: I just spotted this in HWN: [[ * Haskell as a markup language. Oleg Kiselyov [4]writes on using Haskell to represent semi-structured documents and the rules of their processing. [5]SXML is embedded directly in Haskell, with an open and extensible set of `tags'. The benefit of this is of course in static type guarantees, such as prohibiting an H1 element to appear in the character content of other elements. 4. http://www.haskell.org/pipermail/haskell/2006-March/017656.html 5. http://ssax.sourceforge.net ]] I think this really should be in the toolkit, possibly at the heart of the templating system. I think this kind of capability is exactly why Haskell could be so good as a web application language. -- Graham Klyne For email: http://www.ninebynine.org/#Contact

Graham Klyne wrote:
[Switching to haskell-cafe] Niklas Broberg wrote:
...
On 3/6/06, Graham Klyne
wrote: - Options to run the whole thing behind Apache to leverage its security and web space management capabilities
Lemmih has implemented a HSP/FastCGI binding for Apache. I also know that work is being done on building a direct HSP/Apache binding. All work in progress though.
Yes, I was aware of a fastCGI for Haskell. Didn't Bjorn Bringert (also) implement one? I tend to think of CGI programs as run-to-completion-then-exit, even when a fastCGI interface allows a persistent wrapper program to speed startup. But I could easily be missing something here.
Yes, I have written a FastCGI binding (darcs repo here: http://www.cs.chalmers.se/~bringert/darcs/haskell-fastcgi/). If I'm not mistaken, that's what Lemmih is using for his HSP/FastCGI binding. I have only used FastCGI the way you describe, as CGI without start-up penalty, though I can't see why you couldn't keep some state between requests to a FastCGI application. I believe that Ruby-on-Rails (which I've never used, so I'm not too sure) can use FastCGI. One problem with Apache and FastCGI is that the Apache FastCGI module doesn't seem to support concurrent requests to a single FastCGI process (even though the FastCGI protocol allows this). This means that Apache will have to run several instances of the Haskell-over-FastCGI app to serve concurrent requests, or be forced to serialize the requests. Having several instances of course means that you can't really keep stuff like session data in memory in the FastCGI process. If the Apache module supported concurrent requests we could spawn a new Haskell thread to serve each request, which ought to scale well.
...
/Björn

Björn Bringert wrote:
Graham Klyne wrote:
[Switching to haskell-cafe] Niklas Broberg wrote:
...
On 3/6/06, Graham Klyne
wrote: - Options to run the whole thing behind Apache to leverage its security and web space management capabilities
Lemmih has implemented a HSP/FastCGI binding for Apache. I also know that work is being done on building a direct HSP/Apache binding. All work in progress though.
Yes, I was aware of a fastCGI for Haskell. Didn't Bjorn Bringert (also) implement one? I tend to think of CGI programs as run-to-completion-then-exit, even when a fastCGI interface allows a persistent wrapper program to speed startup. But I could easily be missing something here.
Yes, I have written a FastCGI binding (darcs repo here: http://www.cs.chalmers.se/~bringert/darcs/haskell-fastcgi/). If I'm not mistaken, that's what Lemmih is using for his HSP/FastCGI binding.
I have only used FastCGI the way you describe, as CGI without start-up penalty, though I can't see why you couldn't keep some state between requests to a FastCGI application. I believe that Ruby-on-Rails (which I've never used, so I'm not too sure) can use FastCGI.
One problem with Apache and FastCGI is that the Apache FastCGI module doesn't seem to support concurrent requests to a single FastCGI process (even though the FastCGI protocol allows this). This means that Apache will have to run several instances of the Haskell-over-FastCGI app to serve concurrent requests, or be forced to serialize the requests. Having several instances of course means that you can't really keep stuff like session data in memory in the FastCGI process. If the Apache module supported concurrent requests we could spawn a new Haskell thread to serve each request, which ought to scale well.
Aha! I think that homes in on what I was after when mentioning long-running processes. I think there are some separate but related issues to consider: (a) can a single CGI invocation handle (respond to) a series of HTTP requests, or is it strictly one http request for each CGI invocation? Without this, you may have to throw away session state after each request. (b) is there a way to maintain state between CGI invocations? (c) can multiple concurrent CGI/HTTP requests be handled? Of these, I think (c) may be the least important, other than for performance reasons (and maybe not even then), provided that there are ways to handle upstream I/O asynchronously, and to encapsulate all the relevant session state in a way that can be passed between invocations. I guess it comes down to a choice between an event-driven or multi-threaded processing model (and the former seems to me to be a nicer fit with Haskell). I think the minimum requirement is ((a) OR (b)) AND ((c) OR (asynchronous I/O completion)) #g -- Graham Klyne For email: http://www.ninebynine.org/#Contact
participants (2)
-
Björn Bringert
-
Graham Klyne