RESTful Web Services in .NET (Part 2)

Now that I’ve finally got a bit of time I figured I should explain how we updated our old RESTful framework to be nice and slick. Instead of one method per class which handles all sub method variations we now have something much prettier and easier to maintain. The UserService found in the previous post can now look like:

public class UserService : RestService
{
	[RestMethod("GET", "^$")]
	public IList RetrieveAll()
	{
	}

	[RestMethod("GET", @"^(?<id>[0-9]+)$")]
	public User Retrieve(int id)
	{
	}

	[RestMethod("HEAD", @"^(?<name>\w+)$")]
	public User Exists(string name)
	{
	}

	[RestMethod("PUT", "^$", typeof(User))]
	public User Create(User user)
	{
	}

	[RestMethod("POST", "^$", typeof(User))]
	public bool Update(User user)
	{
	}

	[RestMethod("DELETE", @"^(?<id>[0-9]*)$")]
	public bool Delete(int id)
	{
	}
}

As you can see there are a lot of differences:

  • Heavy influence from newer APIs
  • Methods can return any Type
  • Methods can take 0 or more arguments of any Type
  • RestMethodAttribute has been added to match URLs against methods

Most of the code above should be self-explanatory, but in case it’s not here’s some help.

The method decorator [RestMethod("GET", "^$")] tells the framework that any HTTP GET requests against the UserService class without any trailing arguments (http://localhost/user.r) should be handled by RetrieveAll().

The method decorator [RestMethod("GET", @"^(?<id>[0-9]+)$”)] tells the framework that any HTTP GET request against the UserService class which ends with a number only (http://localhost/user.r/1, http://localhost/user.r/5000, etc) should be handled by Retrieve(int id). The cool thing here is that the regex group will provide a match to the argument name so our function will be called with whatever number the URL ends with. So calling http://localhost/user.r/25 where the following is the executed method will result in?

[RestMethod("GET", @"^(?<id>[0-9]+)$")]
public bool Retrieve(int id)
{
	return id == 25;
}

TRUE!! Pretty simple, and very cool. Another nice feature is when the HTTP request contains a body like a POST or PUT would. So POSTing to http://localhost/user.r with a body of:

{'user': {
	'first_name': 'Matthew',
	'last_name': 'Metnetsky'
}}

would call the method decorated with [RestMethod("POST", "^$", typeof(User))] and it’s user argument would actually be set assuming the class implemented a JSON serializer. All of the URL/body mappers are definable by implementing Binder and listing them in the web.config against a Content-Type. By default there are Binders for form variables, JSON, XML, raw streams, and a few more.

So why might I be discussing the external API of a closed library? To PUSH innovation in the current public ones. By taking these ideas and creating an “open” version I’m sure I’d be breaking my contract so I’ve got two options:

  1. Expose our public API to entice and PUSH others to innovate
  2. Get a lot of feedback which might enable me to get our library opened

So…. let me know…. ;-)

RESTful Web Services in .NET (Part 1)

A couple of years ago I tossed together a RESTful IHttpHandlerFactory for .NET. It wasn’t amazing, but it was being used long before Microsoft et all decided to create there own. Instead of extending Page you extended RestService and implemented whatever methods you wanted.

public interface IRestService
{
	void Head(RestEventArgs args);
	object Get(RestEventArgs args);
	object Put(RestEventArgs args);
	object Post(RestEventArgs args);
}

As you can probably guess the request’s HTTP Method was transformed into the function name and executed accordingly. If the method wasn’t “known” we would then use reflection to find the method for execution. Not to fansy as you can see, but it worked.

If a request was made for http://localhost/app/users.r the IHttpHandler factory would load users.r and it would tell us what class you assigned to it (much like @Page CodeBehind/Inherits in .aspx). From there we would instantiate the class and call the appropriate method. Whatever you returned would be marshalled for wire transfer based on it’s type.

	class User : IXmlSerializable
	{
		/* ... */
	}

	public class UserService : RestService
	{
		public object Get(RestEventArgs args);
		{
			return new User(5, "Matthew", "Metnetsky");
		}
	}
}

Calling http://localhost/app/users.r would execute UserService::Get(..) which would return a User instance. The results are then inspected for a few different interfaces like IXmlSerializable, IJsonSerializable (one of ours), etc. Based on what is supported by the Type, we then check if the requester supports it by interogating their “Accepts” header. This way each requester can receive what they understand how to handle (for instance – don’t send JSON to AS3). The system really worked well, and it’s simplicity made it damn fast.

Like all frameworks however, once it was actually in use we were able to see the pitfalls and issues. Take a look at the following URLs:

  • http://localhost/app/users.r
  • http://localhost/app/users.r/1
  • http://localhost/app/users.r/matthew

In order to handle all of the urls above the Get(RestEventArgs) method turned into one big switch/if/else conditional. Some people made it prettier than others, but the result was the same. So about 14 months ago we upgraded our framework – check back soon to see how we did it, and why I’m bringing it up now.

AS3 Reflection

Type discovery, better known as reflection, is rather odd in Flex. There is no type system to describe the types like sooo many languages offer (even PHP5 finally got it right). The closest that I know of is flash.utils.describeType which is quite weird as it returns XML. The DTD for the XML is ugly to me, but everyone has their opinions. A simple class like..

public final class EmployeeTitle extends BaseModel
{
	public var id:Number = NaN;
	public var title:String = '';

	public function EmployeeTitle()
	{
		super();
	}

	public static function fromXML(xml:XML):EmployeeTitle
	{
		return null; /* we should do something important here */
	}
}

turns into the following XML…

<type name="kmbs.model::EmployeeTitle" base="kmbs.model::BaseModel" isDynamic="false" isFinal="true" isStatic="false">
  <extendsClass type="kmbs.model::BaseModel"/>
  <extendsClass type="Object"/>
  <variable name="id" type="Number"/>
  <variable name="title" type="String"/>
  <method name="assignXML" declaredBy="kmbs.model::BaseModel" returnType="void">
    <parameter index="1" type="XML" optional="false"/>
  </method>
  <method name="toString" declaredBy="kmbs.model::BaseModel" returnType="String"/>
  <method name="toXML" declaredBy="kmbs.model::BaseModel" returnType="XML"/>
</type>

As I was looking for a way to marshal the type to XML for pushing to the server it seems like this was the closest I was going to get. So I wrote some code and got the basics working no problem. A few days ago I realized that most of my models would be a bit more useful if they were [Bindable] and thus dispatched events about their changes (lets keep those interfaces up to date eh?). So I added what .NET calls attributes and Flex calls metadata tags.. [Bindable] to my class.

[Bindable]
public final class EmployeeTitle extends BaseModel
{
	/* .... */
}

Once I did this however, none of my XML marshaling was working because apparently the type descriptor is now totally different.

<type name="kmbs.model::EmployeeTitle" base="kmbs.model::BaseModel" isDynamic="false" isFinal="true" isStatic="false">
  <extendsClass type="kmbs.model::BaseModel"/>
  <extendsClass type="Object"/>
  <implementsInterface type="flash.events::IEventDispatcher"/>
  <method name="addEventListener" declaredBy="kmbs.model::EmployeeTitle" returnType="void">
    <parameter index="1" type="String" optional="false"/>
    <parameter index="2" type="Function" optional="false"/>
    <parameter index="3" type="Boolean" optional="true"/>
    <parameter index="4" type="int" optional="true"/>
    <parameter index="5" type="Boolean" optional="true"/>
  </method>
  <accessor name="id" access="readwrite" type="Number" declaredBy="kmbs.model::EmployeeTitle">
    <metadata name="Bindable">
      <arg key="event" value="propertyChange"/>
    </metadata>
  </accessor>
  <method name="hasEventListener" declaredBy="kmbs.model::EmployeeTitle" returnType="Boolean">
    <parameter index="1" type="String" optional="false"/>
  </method>
  <method name="dispatchEvent" declaredBy="kmbs.model::EmployeeTitle" returnType="Boolean">
    <parameter index="1" type="flash.events::Event" optional="false"/>
  </method>
  <method name="willTrigger" declaredBy="kmbs.model::EmployeeTitle" returnType="Boolean">
    <parameter index="1" type="String" optional="false"/>
  </method>
  <method name="removeEventListener" declaredBy="kmbs.model::EmployeeTitle" returnType="void">
    <parameter index="1" type="String" optional="false"/>
    <parameter index="2" type="Function" optional="false"/>
    <parameter index="3" type="Boolean" optional="true"/>
  </method>
  <accessor name="title" access="readwrite" type="String" declaredBy="kmbs.model::EmployeeTitle">
    <metadata name="Bindable">
      <arg key="event" value="propertyChange"/>
    </metadata>
  </accessor>
  <method name="assignXML" declaredBy="kmbs.model::BaseModel" returnType="void">
    <parameter index="1" type="XML" optional="false"/>
  </method>
  <method name="toString" declaredBy="kmbs.model::BaseModel" returnType="String"/>
  <method name="toXML" declaredBy="kmbs.model::BaseModel" returnType="XML"/>
</type>

As you can see all of the variable tags have been replaced by accessor tags. And methods have been added in order to perform the Event handling/dispatching, but apparently the class doesn’t extend something special. Instead the compiler seemingly injects raw methods, which bothers me for some reason.

As you can see I find Flex’s internals rather weird instead of smart, but as I said, everyone has their opinions.

Monthly Calendars in PHP for Flex

At work I recently had a need to create a monthly calendar within Flex and populated with data from a web-service (created in PHP). I hate reinventing the wheel, but I also hate wasting time searching for a solution to a simple enough problem. So below you can find a quick answer to the problem as I couldn’t find one myself.

PHP: The following code creates a simple XML feed.


<?php
	/**
	 * Create a XML calendar for a given year &amp; month
	 *
	 * Noah Massey &amp; Matthew Metnetsky
	 */
	function calendar_xml($doc, $year, $month)
	{
		if (!$doc) throw new Exception('doc is bad');
		if (!$month) throw new Exception('month  is bad');
		if (!$year) throw new Exception('year is bad');

		$numDays = date('t', mktime(0, 0, 0, $month, 1, $year));

		$monthNode = $doc->appendChild($doc->createElement('month'));

		$day = 1 - date('w', mktime(0, 0, 0, $month, 1, $year));

		do {
			$weekNode = $monthNode->appendChild($doc->createElement('week'));

			for ($y=0;$y<7 and $day <= $numDays; $day++,$y++) {
				//$sunday = ($day == $y);
				//$sunday = ($day == ($y + 6));
				$dayNode = $weekNode->appendChild($doc->createElement('day'));
				$numAttr = $doc->createAttribute('num');
				$numAttr->appendChild($doc->createTextNode($day));
				$dayNode->appendChild($numAttr);

				/*
				 * we could loop through database records here for holidays etc
				 * the _real_ version uses mktime(0, 0, 0, $month, $day, $year)
				 * to check for a stamp within an array of holiday records
				 * and then tack on some more nodes to $dayNode
				 */
			}
		} while ($day <= $numDays);
	}

	$doc = new DOMDocument('1.0', 'UTF-8');
	$doc->formatOutput = true;

	$date = getdate();
	$year = (int) (array_key_exists('year', $_GET))? $_GET['year'] : $date['year'];
	$month = (int) (array_key_exists('month', $_GET))? $_GET['month'] : $date['mon'];

	calendar_xml($doc, $year, $month);
	header('Content-Type: application/xml', true);
	echo($doc->saveXML());
?>

If you look at the rather large comment block above you can see where the value comes in. It’s pretty simple to use a unix timestamp to find records which you actually would want in the XML like holidays, events, etc.

The basic output looks like the following, and can be see in full at http://cowarthill.com/blog/wp-content/uploads/2009/01/calendar-xml.php

	<month>
		<week>
			<day num="{day of month}" />
		</week>
	</month>

Once you have all of this in place you need to pull it into Flex. I found using a DataGrid very easy once you have the XML from the web service. And to customize the display I created a custom itemRenderer for the DataGridColumns. Here’s a few snippets….

MXML: Lets define our DataGrid and our HTTPService which will retrieve our data.

<mx:DataGrid id="dg"
	sortableColumns="false"
	draggableColumns="false"
	selectable="false"
	showScrollTips="true"
	horizontalScrollPolicy="off"
	verticalScrollPolicy="off">
	<mx:columns>
		<mx:DataGridColumn headerText="Sunday" itemRenderer="calendar.MonthCell" />
		<mx:DataGridColumn headerText="Monday" itemRenderer="calendar.MonthCell" />
		<mx:DataGridColumn headerText="Tuesday" itemRenderer="calendar.MonthCell" />
		<mx:DataGridColumn headerText="Wednesday" itemRenderer="calendar.MonthCell" />
		<mx:DataGridColumn headerText="Thursday" itemRenderer="calendar.MonthCell"  />
		<mx:DataGridColumn headerText="Friday" itemRenderer="calendar.MonthCell" />
		<mx:DataGridColumn headerText="Saturday" itemRenderer="calendar.MonthCell" />
	</mx:columns>
</mx:DataGrid>

<mx:HTTPService id="calHS"
	url="http://localhost/project/calendar-xml.php"
	method="GET"
	result="handleCalXML(event);"
	fault="Alert.show('Failed to retrieve XML from server');"
	resultFormat="e4x"
	contentType="application/xml"/>

AS3: Now we need at least two functions: 1 to call the service and retrieve the XML; and a second take the response and assign it to the DataGrid.

/* month should be 1-based (January) */
public function retrieveCalendar():void
{
	calHS.url = 'http://localhost/project/calendar-xml.php?year=' + year + '&amp;month=' + month;
	calHS.send();
}

/* handle the results from from calendar-xml.php */
private function handleCalXML(event:ResultEvent):void
{
	var weeks:XMLList = event.result.week as XMLList;

	/* dg is defined above in the MXML */
	this.dg.dataProvider = dayInfo;
	this.dg.rowCount = weeks.length(); // grid show be no bigger than necessary
}

Now we’re going to create a reusable itemRenderer which is instantiated for each cell in the DataGrid. You can do this in MXML directly, but I like AS3. The most important function to focus on is the setter for data because it assigns the values based on the XML we received.

package calendar
{
	import mx.collections.XMLListCollection;
	import mx.controls.TextArea;
	import mx.controls.listClasses.BaseListData;
	import mx.controls.listClasses.IDropInListItemRenderer;
	import mx.controls.listClasses.IListItemRenderer;
	import mx.core.IDataRenderer;
	import mx.events.FlexEvent;

	public class MonthCell  extends TextArea
							implements IDataRenderer, IDropInListItemRenderer, IListItemRenderer
	{
		private var _week:XMLListCollection = null;
		private var _day:XML = null;
		private var _listData:BaseListData;

		public function MonthCell()
		{
			super();

			this.editable = false;
			this.wordWrap = true;
			this.selectable = false;
		}

		[Bindable(FlexEvent.DATA_CHANGE)]
		public override function get listData():BaseListData
		{
			return this._listData;
		}

		public override function set listData(ldata:BaseListData):void
		{
			if (this._listData != ldata) {
			this._listData = ldata;
			this.dispatchEvent(new FlexEvent(FlexEvent.DATA_CHANGE));
			}
		}

		[Bindable(FlexEvent.DATA_CHANGE)]
		public override function get data():Object
		{
			return this._week;
		}

		public override function set data(value:Object):void
		{
			var xml:XML = value as XML;

			if (xml) {
				// convert XML to a list for extra methods
				this._week = new XMLListCollection(xml.children());

				// make sure we've got enough records in week
				// to be able to get the current day
				if (this._week.length > this.listData.columnIndex) {
					this._day = this._week.getItemAt(this.listData.columnIndex) as XML;
				} else {
					this._day = null; // clear in-case we're reused
				}
			}

			// do we have a valid day XML object
			if (this._week == null || this._day == null || int(this._day.@num) < 1) {
				this.htmlText = "";
			} else {
				/* lets display the day of the month in the cell */
				this.htmlText = "<p><b>" + this._day.@num + "</b></p>";
			}

			this.invalidateProperties();
			this.dispatchEvent(new FlexEvent(FlexEvent.DATA_CHANGE));
		}
	}
}