Monday, October 12, 2009

Building a Wishlist Service: HTML Forms

Back to the wishlist service, and it's time to look at the client side. In particular, the mechanism that the client uses to submit requests. XML on the browser is, quite simply, a pain in the neck. While E4X is supposed to be a standard, support for it is limited. Microsoft, as usual, provides its own alternative. Since XML is a text format, you could always construct strings yourself, but there are enough quirks that this often results in unparseable XML.

Against the pain of XML, we have HTML forms. They've been around forever, work the same way in all browsers, and don't require JavaScript. They're not, however, very “Web 2.0 friendly”: when you submit a form, it reloads the entire page. Filling this gap, the popular JavaScript libraries provide methods to serialize form contents and turn them into an AJAX request. As long as you're sending simple data (ie, no file uploads), these libraries get the job done.

To simplify form creation, I created some JSP tags. This provides several benefits, not least of which is that I can specify required parameters such as the user ID and wishlist name. I also get to use introspection and intelligent enums to build the form: you specify an “Operation” value in the JSP, and the tag implementation can figure out whether it needs a GET or a POST, what parameters need to go on the URL, and what fields need to go in the body.

One of the more interesting “learning experiences” was the difference between GET and POST forms. With the former, the browser will throw away any query string provided in the form's action attribute, and build a new string from the form's fields. With the latter, the query string is passed untouched. In my initial implementation I punted, and simply emitted everything as input: the server didn't care, because getParameter(), doesn't differentiate between URL and body. This offended my sense of aesthetics however, so I refactored the code into a class that would manage both the action URL and a set of body fields. Doing so had the side benefit that I could write out-of-container unit tests for all of the form generation code.

The other problem came from separating the form's markup from the JavaScript that makes it work. This is current “best practice,” and I understand the rationale behind it, but it makes me uncomfortable. In fact, it makes me think that we're throwing away lessons learned about packaging over the last 30 years. But that's another post.

No comments: