Archive for the ‘Web’ Category

mod_rewrite, subfolders and trailing slashes

December 30, 2009

I’m posting this because I spent many hours debugging this issue and couldn’t find a single site on the internet that provided a solution. I’m not thrilled with the answer I have, so if anyone knows of a better way to do this, I’m all ears.

The goal

I’m currently starting to host multiple web applications on a single domain in separate subfolders. For example, wordify should be served from http://www.snoyman.com/wordify/. Since I’m using Apache on my host, I need to use mod_rewrite to accomplish this. Anyone who has ever dealt with mod_rewrite probably has the same fear of it that I do. However, I’m purposely not going to go into a mod_rewrite rant.

Anyway, the mod_rewrite needs to make an internal redirect (meaning not changing the user’s URL via a 301 redirect) to the CGI script. For example, I want a request to http://www.snoyman.com/wordify/toword/57/ to be treated by Apache as http://www.snoyman.com/wordify/dispatch.cgi/toword/57/. No problem.

The problem

My initial solution gave a problem when people went to http://www.snoyman.com/wordify. In particular, it would redirect them to a URL based on the absolute filename on the system of the request (eg, http://www.snoyman.com/f5/snoyman/public/…). My temporary solution was to set up a 301 redirect from that ugly URL to the correct location, but that’s not an efficient solution since it requires a whole extra round trip for the user to get to the page.

It turns out that mod_rewrite does funny stuff with converting URLs to pathnames, and there’s no way to specify which type of value you would like to deal with.

The solution

Below is my new .htaccess file. Here’s what you need to know to follow this and adapt it to your own purposes:

  • The root of my website is /f5/snoyman/public
  • All of the wordify files are kept in /f5/snoyman/public/wordify
  • The CGI program for generating the content is called dispatch.cgi
Options +ExecCGI
AddHandler cgi-script .cgi

Options +FollowSymlinks

RewriteEngine On
RewriteRule ^/f5/snoyman/public/wordify$ /wordify/ [R=301,S=1]
RewriteCond $1 !^dispatch.cgi
RewriteRule ^(.*) dispatch.cgi/$1 [L]

A few notes:

  • The first two lines are purely for CGI purposes. You might not need them, or may wish to use different file extensions.
  • The follow symlinks is not needed for the rewrite purposes.
  • The first RewriteRule line does the trailing-slash addition. It specifies R=301 so that the user receives a 301 permanent redirect. The S=1 is a skip option so that the following rule is not executed.
  • The RewriteCond applies to the second RewriteRule, and makes sure we don’t end up with an infinite redirect loop. Remember, mod_rewrite will reloop through all your rules each time one of the rules makes a change to the URL.
  • I’m not sure exactly what the L option does, but it definitely doesn’t guarantee that a rule is the last one executed. That’s why we need the S on the first rule.

It’s ugly, but it works. The only downside I’d like to address is to disallow access from http://www.snoyman.com/wordify/dispatch.cgi/…, but I’m not too worried about that. Following good RESTful principles would make information available at precisely one URL, but the dispatch.cgi is unlikely to be stumbled upon by mistake.

Advertisements

Yesod RESTful web framework sample

December 21, 2009

Update: the example should now be working (as of 2009-12-22 18:10 UTC). Thanks to Chris and Felipe for the bug reports below.

View the sample being discussed here. For full effect, try with and without Javascript.

I’ve been working for a while on a web framework, previously under the name “restful”, but more recently renamed to Yesod. In future posts, I hope to give a more general overview of the features of this framework, but for now I’m just interested in showing a single code sample.

In order to get a nice test suite going, I’ve been racking up simple example web apps. While trying to think of one, I ran across a post on Happstack, which incidentally had a great sample app: factorials. I’m not trying to compare features of Yesod against Happstack here, just give proper attribution for the idea.

The code is available as part of my github repo. I’ve also converted the code to HTML. The file is well enough documented; the rest of this post will try to point out the features of Yesod that make this demonstration notable.

Multiple representations

This is probably the most important piece. Every web framework that exists can generate an HTML page. The vast majority can also generate JSON. Most of them know to set the content-type header correctly (I hope). Yesod, however, takes the same data and can give it different representations.

The trick is in the Yesod.Rep module, in the HasReps typeclass. Any instance of this typeclass can specify multiple renderings of itself. For example, HtmlObject has both HTML and JSON representations (more are possible, but probably unnecesary). You can wrap an HtmlObject with a TemplateFile and then have the data displayed nicely with a HStringTemplate template. To top it all off: HtmlObject handles all the entity encodings for you, so no more cross-site scripting attacks (exaggeration, I know).

Simplified routes

I was always annoyed when using Django that I specified my routes using regexs. There’s no need. I’ve never seen a webapp that did something beyond breaking up pieces across slashes and routing based on that. To get really fancy, you can accept only digits for one of the path pieces.

If you look in the code, you’ll see what looks like a quasi-quoted YAML file. Well, that’s exactly what it is. Yesod includes some Template Haskell to use this YAML file to generate a completely compile-time checked set of routes. It guarantees:

  • No overlapping routes exist.
  • Within each route, there are not duplicate handlers for each verb (request method).
  • Each specified handler takes the right arguments. For example, the resource path “/user/#userid/variable/$varname/” would require a function that takes an Int (for the #userid) and String (for the $varname).

There is also a version of the TH function which does not check for overlapping patterns.

Swappable backends

This example uses the hack-handler-simpleserver so it can be easily tested on a local system without running a web server. However, swap that for hack-handler-cgi, and you’ve got a CGI program. In fact, it will work with any Hack handler.

Various features

There’s a bunch of features in use here under the surface, such as automatic URL cleanup (trailing slashes and the like), JSON-P support, etc. There’s even more power not being used: OpenID authentication, client-side encrypted session data, request method override, etc. These will all be documented before release.

Conclusion

Yesod has been in development for quite a while now (over a year I believe). It’s the core for a few of my sites (photoblog is the largest), and is rapidly approaching its first release. It’s been on hold while some of its underlying libraries matured (failure, attempt and data-object). However, if you’re interested in building Ajax sites following RESTful principles, it could very well be the framework you’re looking for.

From Dreamhost to NearlyFreeSpeech.net

November 29, 2009

Well, I’d toyed around with the idea for quite a while, but when SSH when down for a few days at Dreamhost, I decided it was time to finally make the switch.

The easy part was moving off static sites and getting my personally hosted blog onto wordpress.com. Then of course is the real challenge: a Haskell site.

First shot: compile on the server

Since NearlyFreeSpeech.net (henceforce NFS) claims support for GHC, I thought I’d try out compiling on their servers. My first issue was that they only have 6.8.3, whereas some of my libraries require 6.10. I e-mailed them about this, and they let me know that their unstable server had it available. Switching over was painless.

However, I had a few problems with this approach:

  1. cabal-install would not link due to memory constraints. I can manually install all the libraries I need, but that’s a real pain.
  2. All the files I ended up using used up 250MB. NFS charges per megabyte of storage, so I didn’t feel like wasting time.
  3. As usual with shared hosting, compiling is slow. It’s not as horrible as Dreamhost, where they kill the compiles regularly, but still not as nice as using my shiny new system at home.

Upload binaries

So I can of course just compile my binaries locally and upload them, right? Well, I don’t happen to run a FreeBSD box. I’ve been itching to try out VirtualBox for a while though, and this seemed like a good time to do it.

I know what you’re thinking: I’m a masochist, and this is overkill for this kind of project. However, setting this up didn’t actually require too much work, and it’s a much more durable solution than trying to compile binaries on some flaky shared host (looking at you again Dreamhost).

Anyway, the process was very straightforward:

  1. Download the FreeBSD 7.2 ISO (NFS beta realm runs 7.2).
  2. Install VirtualBox locally.
  3. Install FreeBSD. It’s not too complicated. But make sure you set aside enough hard disk and RAM.
  4. Update ports collection. This was the worst part for me, since I’ve never used FreeBSD before. Also, I tried a selective update at first: bad idea. Just update the whole thing.
  5. Install ghc. Basically, “cd /usr/ports/lang/ghc && make install”. It takes a *long* time as it installs everything.
  6. Compile the binaries inside FreeBSD. I used git/ssh to transfer to projects over to the virtual machine, which was very convenient.
  7. Upload binaries and call it a day.

Other notes

I have opted not to use NFS for my large static file hosting. I’m using the Amazon S3 service, which so far I’ve found to be much faster than Dreamhost. It’s a little tricky to get started though. I was able to sync all my photos using s3sync.

Also, don’t forget to strip your binaries before uploading them, it can save a lot of time.

NFS only supports CGI. This is fine for my purposes, but others may not be so happy with it.

Finally, NFS recently started charging $0.01/day for dynamic sites. It’s only $3.65 a year, but if you’re like me and like to have lots of different sites running, it might add up. I’ll probably just end up running services under the same domain name instead of separate subdomains.

Conclusion

Well, I won’t give my full stamp of approval on this yet, but so far I’m impressed. I’ll try to post some follow-up on this in the future.

Restful, data-object changes

September 16, 2009

It’s been a while since I’ve posted. Mostly, I’ve been refactoring my restful library and writing some code that actually uses it. That’s usually the best way to get a better API after all.

I doubt these projects will really interest too many people, but here they are in case you are interested in some real-world Hack and Restful code:

  • review-minder is used to keep track of information I’ve learned (let’s say vocabulary words) and remind me to review them at certain intervals. For coolness, those intervals happen to be the fibonacci sequence.
  • photoblog is the software I use for running my son’s photo blog.

Underlying things about both of these programs:

  • They use my yaml library, and thus also data-object. I switched from JSON because Yaml is more ammenable for version control software.
  • They have Ajax interfaces based on jquery. Photoblog is in particular interesting: it has a javascript-disabled interface available, and uses jquery-history for the dynamic interface (you know, that stuff after the # in the URL).

I made some updates to data-object recently which I consider to be questionable, so I’m not sure it will last. I ran into some Haskell brick-walls when trying to make these changes; hopefully the next post will describe the problem, my current solution, and what I wish Haskell would let me do.

Final note: restful is nowhere near API stable, which is why I haven’t released it to Hackage. If anyone is interested in using it, or has some suggestion, please send them along. I’m currently not rushing this project so I end up with a nice, clean API.

hack-handler-webkit

July 8, 2009

So I had the idea the other day to make it possible to turn Hack web applications into standalone GUIs. I prefer writing web apps to desktop apps with, for example, GTK, so being able to run arbitrary web apps as if they are simply desktop ones would be a big boon for me. Plus, it means you can live the dream of writing an application once and having it run client-server and locally.

I ripped off the sample for the GTK Webkit port, removed some of the features (I decided I didn’t want back/forward buttons or an address bar), wrote some FFI code, combined it all with hack-handler-simpleserver, and created hack-handler-webkit.

Caveats:

  • The code is not incredibly beautiful, especially since I’ve never written FFI code before (hack-handler-fastcgi was just a ripoff of the original fastcgi package).
  • I’ve only tested it on Ubuntu Jaunty. It doesn’t really do much checking, just uses pkg-config to check for the existence of the webkit-1.0 package. I doubt this will work for other distributions.
  • As stated above, it uses the GTK port. I would like to get this working for Windows and Mac as well, without using the GTK port. If anyone would like to fork this on github and add that functionality, it would be much appreciated.

If you’re running Ubuntu and wanted to give this a try, do the following:

  1. apt-get the correct stuff. I think you’ll just need libwebkit-dev (ie, apt-get install libwebkit-dev).
  2. Download hack-handler-webkit from github and install it. It’s not an hackage yet for obvious reasons.
  3. I branched the hack-samples package I spoke about last week to use this webkit backend. Go ahead and try that out.

Comments, suggestions and bug reports are much appreciated!

Hack Introduction

June 28, 2009

There’s been some noise– and confusion– recently about hack. Hopefully this post can address some of the issues.

What it is

Hack is a webserver interface. This means, it defines a protocol for allowing web applications to talk to different web servers. For example, I can write a web application to use the Hack protocol and then easily switch backends from CGI to FastCGI to Happstack.

Hack is authored by Jinjing Wang.

What is isn’t

  • A web server. This is just a protocol for talking to web servers (see handlers later on)
  • A framework. If you’re looking for a Rails replacement, you’re looking in the wrong place. However, if you want to write a Rails replacement, I would recommend Hack as a good base for it.
  • A coffee maker.

Architecture

The architecture is very simple. Hack defines the following:

Env

The Env data type is essentially the request object. It has the query string, the POST body, HTTP headers, etc. Notice I said query string and not get parameters. In an effort to keep the protocol as light weight as possible, there is not query string processing, POST parameter processing, cookie handling, etc handled by Hack. The application must handle it all.

That said, there are a few options:

  • Write all the processing code yourself.
  • Use my web-encodings package, which handles processing of those fields.
  • Use a hack frontend library (see below).
  • Use a framework. None are available right now, but I’m working on a Restful front controller. That’s what I currently use for a few sites.

Response

Response is simply the output of an application for a single request. It is the status code, HTTP headers and body. Remember, we’re talking low level here: you don’t have any high level templates or Haskell-to-Javascript converters at this level. That’s where a framework would come in.

Application

An application is just a “Env -> IO Response”. It takes a single request and generates a response. As a little piece of advice, if you want to have long-running processes (like with FastCGI) and don’t want to have to reload your data every time, use currying! (Hopefully, my next post will be a sample Hack application which will do just that. I appologize for the lack of examples here, but I’m trying to just give an overview.)

Middleware

Some tasks are going to be performed by many applications, and thus it would be a waste to force each application to reimplement that functionality. For example, do you want to have to write gzip compression into every application you write? I thought not. Therefore, middleware just takes an existing application and wraps it with extra functionality. Two notes:

  1. You can use multiple middlewares at once. I use, for example, cleanpath, clientsession, gzip and jsonp.
  2. The order in which you apply these matters. (Again, hopefully more details on this in the next post.)

Handler

A handler is simply a function with the type signature “Application -> IO ()” (or something similar enough). Basically, it’s what “runs” your application. Jinjing has written a number of handlers, but I’m not very familiar with those. I’ve written three which I use on a regular basis, so I’ll describe them here.

hack-handler-cgi

Run your application as a regular old CGI application. If you don’t know about CGI, you probably should do a little more research into web programming before attempting Hack.

hack-handler-fastcgi

Simply wraps up hack-handler-cgi with the FastCGI C library, in the same way that the fastcgi package wraps up cgi.

hack-handler-simpleserver

This is a little standalone HTTP server that I wrote. It is not meant to be production quality. I only use this for debugging purposes (ie, so I don’t have to set up Apache on my local system). Caveat emptor.

Frontend

I wrote a monadcgi frontend for kicks, and now looking at Hackage I see Jinjing also wrote one for happstack. Not being familiar with that package or Happstack, I’ll just address the monadcgi one.

Basically, there has been a CGI library around for a while that defines a CGI monad. There are two problems with this:

  1. Some people (including me) think that the approach chosen for the library is too “object oriented”.
  2. If you write code for this library, you’re stuck with CGI (or FastCGI with the fastcgi package).

Using the monadcgi frontend for Hack, you can take any application written for the old CGI monad and make it work with any Hack handler.

Conslusion

Hack is in its infancy right now; don’t let the large number of Hack packages on Hackage let you think otherwise. Nonetheless, some of us are using it in production settings now with great success. The documentation is lacking, but on the other hand, Hack is so incredibly simple that it doesn’t really need documentation. In any event, I hope to rectify the documentation issue with some code samples soon.

Also, I’d like to address some potential criticism: Hack does not solve many problems. I’ve heard that people are considered with leaving file handles open, database locking, etc. These are real issues that plague us all in web development. However, this is not Hack’s concern. Hack simply let’s your application talk to a handler. Period. You still need to figure out if you want to use HSP or the html library, if you’ll use jquery or HJScript, or if you’ll go the HDBC, Takusen or happstack-state route.

No. Hack ignores all these issues, and hopefully will allow people around the Haskell community to begin to standardize our web development practices in at least one arena.

Wordify: RESTful Haskell web apps

May 20, 2009

Here’s an incredibly simplistic Haskell RESTful web application. If you look at the code, Web.Restful is the beginning of a proper RESTful framework, built on a bunch of smaller libraries I’ve been uploading to Hackage recently. Once I’ve stabalized it a bit, I’ll release it as its on library. For now, it lives in wordify-web and some personal site.

Anyway, here’s wordify!

Run a MonadCGI as a CGI application!

May 20, 2009

That title should have you a little bit confused. “Isn’t that the whole point on the cgi package?” Well, yes. But I’m going to give you a brand new way to do exactly the same thing. Hopefully, you’ll agree with me by the end that this is a pretty good idea.

I’ve been working on Hack (by Jinjing Wang) a bit recently. Its goal is to provide a universal interface for Haskell web applications, similar to WSGI in Python or Rack in Ruby. So we now have a whole bunch of handlers for hack, which means you could write a hack application and get it to run on any of those backends. So, part of my dream framework can be realized: write the app once, test it locally on a simple HTTP server, and deploy it using FastCGI.

So for fun, I decided to also write a Hack frontend which allows you to take existing applications written against the existing cgi package and run them on Hack. The code is inanely simple thanks to the modularity of both the Hack library and the CGI library. Here is an example of how to convert a CGI application to a CGI application (going through Hack):

Old code:
import Network.CGI
main = runCGI mainCGI
mainCGI = output "This is a test"

New code:
import qualified Network.CGI
import qualified Hack.Handler.CGI
import qualified Hack.Frontend.MonadCGI
main = Hack.Handler.CGI.run $ Hack.Frontend.MonadCGI.cgiToApp mainCGI
mainCGI = Network.CGI.output "This is a test"

Now, you can of course make the mainCGI much more complicated, and replace Hack.Handler.CGI.run with any of the other Hack handlers available on Hackage. I’m hoping that this code drops the barrier to entry on Hack so we as a community can start sharing libraries more. Just look for hack-frontend-monadcgi on Hackage.

Also, in case anyone is wondering what happened to Yesod, I’ve decided to change my approach a bit. Instead of writing my own brand new framework which will probably not be used by anyone, I’m trying to write a bunch of smaller, useful libraries. I hope others follow suit, and that when we have a number of mature packages for handling individual tasks, we could simply stick them together into a very nice framework. I appreciate feedback on this point.

First (real) Yesod commit

January 31, 2009

OK, I’ve gotten the first real code commit to Yesod. There are a few decisions that I made with this commit:

  • I’d originally intended to put generic web utilities in a separate repository. I changed my mind with this one, deleted my webutils repository on github, and merged all the code into Yesod. This should make it easier to maintain.
  • The name given to this first bit of code is the “backend” code. This includes the definition of a request and a response, and the definition of an application (Request -> IO Response) and an adapter (something which runs an application).

The only adapter included in this commit is Standalone, which- as you might guess- runs a standalone server. I will include CGI in another commit, and then barring bug fixes, that’s about all I want in the backend code. I do want to have a FastCGI adapter, but I don’t want the fastcgi dependency to break building on systems without the C library, so I’d prefer to have a separate yesod-fastcgi repository. That would be a great project for anyone looking to contribute…

Also, I’ve included an “examples” directory. I’m hoping to keep this populated with more and more advanced examples as the framework progresses to give guidance to new users. Nonetheless, I do not expect that to be a replacement for good documentation; this framework will hopefully have both full Haddock documentation and more tutorial-oriented documentation at the appropriate time.

The next piece to work on will be the controller. So if anyone has any architectural ideas, speak now or forever hold or peace. The one thing I am thinking right now is: KEEP IT SIMPLE. It seems like everyone insists on using regexs or parsers for handling routing. I just have to ask: why? I’ve never heard of routing that does something much more complicated than dealing with a path like a filesystem path, ie separating on the slashes.

So here’s my idea: allow some kind of super-general function for advanced routing, but have a simplified interface for the usual case. If that sounds too vague, then just wait for the code to be available ;).

Haskell Web Framework

January 25, 2009

I haven’t said much on the Haskell mailing lists, though I’ve been following them for the past few months. I’ve been using Haskell for close on a year now, and must say that I love it. What I would especially love would be to create websites in Haskell, which is where this post comes in.

Before someone jumps in with a framework suggestion of HAppS or Turbinado, they are simply not options for me (and I assume many other people) because I am stuck with shared hosting services. The only framework I’ve seen so far that seems to be shared hosting-friendly is Kibro, which- although great for its purpose I’m sure- simply does not give the features I’d be looking for in a framework.

I’m not trying to claim here that these other frameworks are The Wrong Way and that I have created a framework that does it The Right Way. So far, I have written some code, but I know that, by myself, I won’t be able to get it to handle everything that it should. I’m hoping to engage others here in some brainstorming, and perhaps ultimately collaborating on code, to design a much more complete web framework.

I have thought quite a bit about some portions of the framework, whereas for others (most notably models) I don’t have anything coherent thought out. So my idea was to throw up all my thoughts here and get people’s feedback. If you think my ideas might be a good basis for collaborating on a Haskell web framework, then we can move on from there. Otherwise, I guess I’ll return to the torture which is (PHP | Python | Ruby) coding.

  1. We should have something similar to WSGI. This way, the same application can be used running its own server (especially useful for testing), CGI, FastCGI or even mod_haskell. You can see my idea for this generic typeclass in Web.Server.Service.WebServer. I don’t have my heart set on most of that interface, except for the next item.
  2. Approot is very useful. Basically, I think every request should carry along with it the following two pieces of information: the URL to the root of the current web application, and the path to the current page within the web application. For example, if I write a web application and am running it with the test server on port 8080, and go to the URL “http://localhost:8080/foo/bar/”, the approot is “http://localhost:8080/” and the path is “foo/bar/”. This becomes very useful when you then stick your web application in a subdirectory of another site, so that the application home page is http://www.example.com/myapp/. Then if you go to http://www.example.com/myapp/foo/bar/, the approot is http://www.example.com/myapp/ and the path is foo/bar/.
  3. By convention, each web application should have a “static” directory for images, CSS, JS, etc. Then, we can automatically generate .htaccess files for (Fast)CGI versions of the site that show those files, and the built in server would know to display those.
  4. Now pulling points 2 and 3 together a little bit: there is a built in concept of internal versus external links. This might be represented as data Link = ILink String | ELink String. You could then create a function to convert the links into URLs as so: urlFromLink :: Request -> Link -> String
    urlFromLink _ (ELink s) = s
    urlFromLink req (ILink s) = approot req ++ s
    This way, the link ILink "static/images/cutecat.jpg" will turn into either http://localhost:8080/static/images/cutecat.jpg or http://www.example.com/myapp/static/images/cutecat.jpg
  5. User authentication should be built in. I like the idea of basing it around OpenID with options for logging in with e-mail addresses, and then having a built in interface for linking OpenIDs and e-mail addresses together into a single account, but I’m flexible on this point.
  6. Another flexible point: we should store session data in encrypted client cookies. I believe I read about this first with Rails 2.0, and that it is apparently supposed to be much faster since it doesn’t require file access for every request. I know that in the past I’ve been bitten by concurrent writes to SQLite databases when writing session information, and this can help.
  7. We should use UTF-8 everywhere and for everything. I suppose we should make it possible for someone to use a different encoding, but UTF-8 is the right answer 99% of the time IMHO.
  8. When it comes to models, I am torn between “let’s build a great ORM” and “relational databases are awesome.” My day job is an actuary, so I am very comfortable with straight SQL, but I understand that other people are not. There is also the issue of type safety to deal with. I defer on models to those wiser than I here.
  9. I really like the idea of generic views, though the implementation obviously depends greatly on how we do models, so I don’t have any clear ideas on this yet.
  10. The framework should handle any type of response, be it an image, a plain text file, XML, JSON or HTML. However, we should have a very high-level framework for generating interactive HTML pages that include AJAX functionality. This last piece is broken up into sub-parts, and makes up the rest of the items.
  11. I’ve always been irked by the thought of treating <head> and <body> content as the same thing. For example, most frameworks allow you to specify, somehow, a layout for other HTML pages. This layout usually looks something like this:<html> <head> <link rel='stylesheet' href='style.css'/> <title>[...]</title> </head> <body>[...]</body> </html>
    See the problem? You have to supply two separate hooks to fill in content in the template: one for the title, one for the actual content. Now, let’s say that you want one page to have an additional stylesheet, or some javascript. You need to make even more hooks available. Instead, I think that we should specify our layouts and pages in something similar to the following:
    data Tag = Tag { isHead :: Bool, name :: String, attrs :: [(String, String)], children :: [Tag] } | TagRaw String
    type Page = [Tag]

    myPageContent :: Page
    myPageContent = [Tag True “link” [(“rel”, “stylesheet”), (“href”, “mypage.css”)] [], Tag True “title” [] [TagRaw “My Page”], Tag False “h2” [] [TagRaw “My Page”]]

    layout :: Page -> Page
    layout content = [Tag True “link” [(“rel”, “stylesheet”), (“href”, “layout.css”)] [], Tag False “h1” [] [TagRaw “My Site”]] ++ content

    myPage :: Page
    myPage = layout myPageContent

  12. User input validation should Just Work. If you specify that a box should be a date, then you should automatically have client- and server-side validation of the content without having to think about it. Along the same lines, you should automatically get a date picker attached. The same theory applies to all input types. This should interact perfectly with the model portion as well.
  13. It should be possible to have the output of one piece of the page be dependent on some other part. For example, let’s say you have an input box on the page for someone’s birthday, and elsewhere an output box for their age. We should be able to simply specify the algorithm necessary to calculate an age from a birthday, and the framework will convert this into both client- and server-side code, so that if Javascript is available, the user will immediately see his/her age; otherwise, it will show up after hitting submit.
  14. Related to the previous note: sometimes it is not possible to generate these results client-side. Take, for example, a drop-down list of blog entries to choose from. If the user selects a new entry, there is no Javascript in the world that can automatically determine the content of the post without consulting the server. So I think we need something like the following: when the framework knows that the server will be consulted for some information, it will automatically generate a controller for that information in JSON format (or XML, I’m not very particular on that issue). Then, when the user selects the drop-down box, it will run an AJAX query to download the content and update the page. If javascript is unavailable, the new content will be filled in after hitting submit.

Sorry for my verbosity, but I wanted to get all these ideas into one place and open up a forum for discussion of them. Once again, if this sounds like a good idea to anyone else, and others would like to help brainstorm and implement this in Haskell, let me know. If you think this is a stupid idea, let me know that too ;-).