HTTPService, xmlDecode, ObjectTranslator, and RabidSquirrels

Often when developing a client-server application, it's desirable to keep your object model / value objects in sync between these two tiers. Simply put, this means having identical object representations on both the client and the server. The reason for this is, it keeps the codebase manageable and ultimately makes for a saner development environment. For example, if you're dealing with a RabidSquirrel class on the client-side you can rest assured that its frothingMouth property will be of identical naming and type when you receive it from the server. No guesswork. The only gotcha with this communication design decision is usually the implementation of an elegant transport strategy capable of taking a serialized model from one tier, deserializing it, and converting it to the respective strong-typed model on the other tier. The less this logic needs to know about the particular objects it's serializing and deserializing, the better.

The typical transport mechanism for this design pattern is our boy, XML, which despite it's faults (bloatedness, no strong-typing support, etc) is extremely well supported, especially by Flex. E4X notation and all kinds of XML convenience classes make XML parsing a breeze, allowing the developer to take an XML response via ResultEvent.result in an HTTPService result handler and start playing around with its data with zippy developmental overhead. The problem, again, lies in the actual conversion of this response to a strong-typed object. Often, developers will manually populate typed objects with the XML values within the HTTPService result handler. Unfortunately, this makes any changes to the model annoying, as now, each of these manual translations will most likely be affected.

This brings us to one of Flex's most well-hidden gems ... the HTTPService.xmlDecode property. When you pass the HTTPService.xmlDecode property a function reference, that function will be passed an XMLDocument object as its only parameter, which is generated automatically by the service. You can then take that XMLDocument, iterate through it, building and returning objects of whatever type you desire. When you access ResultEvent.result in your handler function, that property value will be typed based on your decoder return type. So ResultEvent.result is now, say a RabidSquirrel object, rather than a RabidSquirrel XML node representation.

The beauty of this strategy is, at any point, your transport mechanism becomes disposable. If you suddenly decide to switch from XML to JSON (woot!) as your serialization strategy of choice, you only need to code some decoder / encoder functions, and you're done. No need to change anything else.

This is probably best implemented with Darron Schall's ObjectTranslator class, which is capable of taking a raw Object and returning an instantiated strong-typed object in return. Combine this with AS3's SimpleXMLDecoder class, and you've tada, you're done. Here's a simple example:

    The HTTPService Definition (note the resultFormat="object")

    Decoder Method

And there you have it. If you ever wanted to change the model, short of modifying the classes, you wouldn't need to do any additional work. Personally, I favor JSON and have adopted this strategy as such, using the as3corelib JSON serialization tools. One significant benefit over XML is the typing that JSON supports, therefore making recursive graph deserialization much much simpler. The only thing to keep in mind, is that your decoder function will still need to accept an XMLCollection. However, you can always grab the firstNode value off this object for the full-text response of your non-XML serialized String.

EDIT: Below is an example implementation of recursively typing an untyped object as it is decoded. This is currently handled in a JSON implementation, but it should be easily portable to an XML implementation. Note that it is dependent on Darron Schall's ObjectTranslator class. I hope this helps some people out!


About this entry