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

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

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

Graham Klyne-2
[Switching to haskell-cafe]

Niklas Broberg wrote:
> Ehum, shameless plug. :)
>

Pretty much what I was fishing for...

> On 3/6/06, Graham Klyne <[hidden email]> wrote:
>> Cale Gibbard 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
>> 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


_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Web application frameworks

Bjorn Bringert-2
Graham Klyne wrote:
> [Switching to haskell-cafe]
> Niklas Broberg wrote:

> ...

>>On 3/6/06, Graham Klyne <[hidden email]> 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
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Web application frameworks

Graham Klyne-2
Björn Bringert wrote:

> Graham Klyne wrote:
>> [Switching to haskell-cafe]
>> Niklas Broberg wrote:
>
>> ...
>
>>> On 3/6/06, Graham Klyne <[hidden email]> 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

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe