In this tutorial you'll learn how to use the exyus engine to build a simple task list web application. This also covers the process of defining HTTP resources using the XmlFileResource base class that supports basic REST constraints. In addition, you'll learn how to define XSL and XSD documents to handle mime-types and PUT/POST validations for the resource. Finally, you'll see examples of simple client scripting and CSS to add client-side functionality and styling to the web app.
You can test the online version of the TaskList application.
Feedback and comments are welcome via the Exyus Discussion Group.
The process of implementing a this Task List web application is fairly simple. First, you need to determine the data you wish to capture as a "task" object along with the functionality you want to support (adding, editing, and deleting tasks from a list). In this example, HTML will be one of the supported content types. That means you need to create a minimal XHTML markup to support displaying and updating the list of tasks.Eventually, you need to add client scripting to support the determined actions and CSS styles to lend a better 'look and feel' to the app.
Along with the client-side work of authoring an HTML UI w/ scripting and styles, you need to implement a server-side HTTP resource to respond to the HTTP methods and support the accepted content types. In this example, the HTTP resouce will be built using the XmlFileResource base class. That means the data will be stored on the server in a structured (XML) file. The XmlFileResource class uses XSL transforms for each supported content-type to render responses to the client. In this case, you need to create transforms to render XHTML and XML to the client. The XmlFileResource class also uses XSD schema to validate content sent to the server via HTTP PUT and POST. For the purposes of this tutorial, we'll only support POST for HTML FORMS. We'll support both POST and PUT for the XML content-type. This is an arbitrary decision that makes the article a bit shorter, but still illustrates how the exyus engine can be used to support multiple content-types for the same HTTP resource.
Once the server and client resources are implemented, you need to also configure the exyus engine to set the authentication and authorization rules for the new HTTP resource.
topBefore deailing with the details of coding, the first step is to explicitly outline the data elements to work with, the content-types you wish to support, and the actions you plan to allow for the resource. You also need to determine the URL patterns to which the HTTP resource will respond. Once these decisions are made, implementing the HTTP resource and authoring the transforms and validators will be fairly straight-forward.
For this example, a single "task" object is needed to track a set of tasks in a list. To make this as simple as possible, this web app will need only three elements of data:
Since this example will use the XmlFileResource class, we need to define an XML document that will represent the data elements above. Here is a simple XML document definition for the task object:
<task> <name /> <is-completed /> </task>
Note that the XML document does not include an id
element. The
XmlFileResource
creates unique id elements for all data sent via the HTTP POST command. We'll use this unique
value as the id
for the task.
One of the key features of the exyus engine is that it makes it relatively easy to support multiple content-types for the same HTTP Resource URL. For this example, we'll support both HTML and XML as content-types. HTML will be used as the default type to make it easy for Web browsers to interact with the resource. The XML content-type will make is possible to use javscript and the XmlHttpRequest object to provide an Ajax interface to the task data.
It should be noted that XML (text/xml
) is not a very useful "content type" for building HTTP applications. Other content types that would be more useful would be Atom (application/atom+xml
) or RDF (application/rdf+xml
). However, for this example, we'll use XML to keep things as simple as possible. If you wish, you can use this example as a starting point to add support for your favorite content type.
The "action matrix" is a simple table that shows the actions supported for the HTTP resource along with the content-types, document bodies exchanged and the typical response code. This matrix will be used to implement the actual resouce class and it's associated transforms and validators. The action matrix also details the URL patterns supported by the HTTP resource. The exyus engine allows you to map URL patterns directly to the resource class. This is how the web server handles dispatching HTTP requests at runtime.
Since our example will support the actions of add, edit, and delete for tasks objects, we will need to provide support for the GET, POST (add), PUT (update), and DELETE HTTP methods. GET will return either a list of tasks or a single task (if the task id is part of the URL). POST and PUT will expect the task data as input. And DELETE will use the task id in the URL.
Below is the action matrix for our example task object.
Method | URL | Content Type | Request Body | Response Body | Status |
---|---|---|---|---|---|
GET | /tasklist/ | text/html | task list and form | 200, 404 | |
text/xml | task list | ||||
/tasklist/{taskid} | text/html | task object | |||
text/xml | task object | ||||
POST | /tasklist/ | application/x-www-form-urlencoded | name/value pairs | 302, 400 | |
text/xml | task xml document | ||||
PUT | /tasklist/{taskid} | text/xml | task xml document | 200, 400, 404 | |
DELETE | /tasklist/{taskid} | text/xml | 200, 404 |
Since this example will support HTML Web browsers, we need to build an HTML page that will show the list of current tasks, and their status. It should also show controls to add a new task, change the status of a task, and delete a task. Below is a minimal HTML markup that contains all the elements that are needed:
<?xml version="1.0" encoding="utf-8"?> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <!-- simple markup example for task list --> <title>my task list</title> </head> <body> <h1>my task list</h1> <ul> <li> <a href="#">o</a> <a href="#">x</a> <span>task 1</span> </li> <li> <a href="#">o</a> <a href="#">x</a> <span>completed task</span> <span>[d]</span> </li> </ul> <form method="post" action="."> <fieldset> <legend>Add a Task</legend> <input type="text" name="name" value="" /> <input type="hidden" name="is-completed" value="0" /> <input type="submit" value="add task" /> </fieldset> </form> </body> </html>
A more complete document that includes all the ncessary 'hooks' for attaching javascript events and CSS styles can be viewed here.
topOnce the action matrix and the client markup are completed, you can implement the server-side HTTP Resource with which clients can interact. All resource classes within the exyus engine have a pre-determined set of methods. These are:
As you can see from the list above, these methods correspond to the standard HTTP commands. The exyus engine automatically routes HTTP requests to the resource to the appropriate method. This is handled by 'decorating' the resource class with the UriPatterns attribute (see the sample code below). Adding these patterns is all you need to do. There is no need for a "resource map" or any other code to handle request routing.
The base classes are also designed to make it relatively easy to add support for multiple content types. This is handled by adding a list of content-types (via the MediaTypes attribute) to the definition of the class. Like the UriPatterns attribute, this is a direct association and there is no other code needed in order to inidicate support for one or more content types.
The exyus engine also supports standard caching directives to optimize client-server interactions. This is handled via functions in the Cache.cs class that are called within the handling of the GET and HEAD requests. TheIsCachedResouceValid()
and CacheResource()
methods are available for handling this step.
This version of exyus is built for ASP.NET over IIS running on Windows XP and higher. The runtime was written in C# 2.0 using Visual Studio. However, to build and run this sample, you only need the command-line C# compiler and a running version of IIS with ASP.NET 2.0 installed. You also need to download and configure the exyus runtime for you web server.
For the task list example, we'll use the XmlFileResource class since it is very easy to set up. Using the action matrix from above, we can also set the URI pattern, content-type, and support for HTTP methods all in the class declaration. You can view the C# source code for the TaskList.cs resource class online. This is all the compiled code that is needed in order to publish an HTTP resource that supports GET, POST, PUT, and DELETE methods.
Note that theDocumentsFolder
and theStorageFolder
values have been initialized to the location of the XSL/XSD documents and the file storage locations, respectively. When you install this HTTP resource on the server, you need to make sure these physical folders exist on the web server.
Once the HTTP resource has been compiled as a .NET assembly, you need to copy that assembly DLL
to the BIN folder at the root of the ASP.NET web application. For standard installations, this
is the /exyus/bin/
folder.
Before you can access the /tasklist/
resource on the web server, you need to configure
the proper security. There are two steps in this process. First you need to configure the URL
for authentication and second, you need to configure the URL for authorization (access rights).
Setting the authentication for a URL is done by making an entry in the config/auth-urls.xml
file. The line below shows how to configure the /tasklist/
URL to allow anonymous
users to access the resource:
<url path="/xcs/tasklist/" auth="false" />
Setting the authorization for a URL is done by making an entry in the config/auth-users.xml
file. Add the line below to the anonymous user's list of permissions. Ths will grant authorization to
all users for all the standard HTTP methods (GET, POST, PUT, and DELETE):
<permission path="/xcs/tasklist/" methods="*" />
NOTE: Usually resources that allow users to edit server objects will be set to require authentication. But for the purposes of this example, we'll allow all users to edit the task list.
Once you have compiled and configured the HTTP resource, you're ready to create the XSL transforms and XSD validators for the resource to use at runtime.
topMany of the HTTP Resource classes in the exyus engine use XSL transform documents to handle incoming requests and format outgoing responses. Transforms are used in three important cases:
When exyus recieves an HTTP request, the URL is broken down into a set of parameters that can be used throughout the processing of the request itself. Other information about the request is also available including any HTTP cookies, the username of the logged in user, the arugments passed in the query string of the URL, etc.
It is common to create an XSL transform to inspect the URL of incoming requests to return the document id on the URL. This value is required for the HTTP PUT command and is also useful for the HTTP GET and HTTP DELETE commands. The document id is forbidden for most HTTP POST commands. For this example application, we'll need this transform to make sure the document id is present in the URL for only the appropriate HTTP methods.
To support this transform, you need to create a file in the resource's Documents folder (see the
DocumentsFolder
setting on the C# class above) called args.xsl
. You can
view the contents of the args.xsl file online.
Notice that the XSL transform expects an incoming xsl:param
named taskid
.
This is the same parameter outlined in the UriPattern
associated with the
TaskList.cs
resource class created in the previous section.
Since the resource is marked to support both text/html
and text/xml
content types, we need to create XSL transform documents that will supply the proper responses
for the HTTP Get methods. Like most resources, the GET method is used to return either a list
of items (GET /tasklist/) or a single item (GET /tasklist/{taskid}). For the text/xml
transform, we need to write code that supports both these "modes" of the GET request.
The runtime looks for transform documents named based on three indicators:
For this example, the document used to transform the output of a GET request for a content-type
XML query from a client will be named: get_response_xml.xsl
. Note that the three
key indicators are used to build up the name of the document: [method]_[state]_[type].xsl
.
All XSL transform documents for exyus use this
naming pattern. You can view the contents of the
get_response_xml.xsl
file online. This file must be placed in the Documents folder as defined for the resource.
You can view typical XML output from this transform for a list request (GET /tasklist/) and for a single item request (GET /tasklist/123)
Note that the XSL transform uses the$_mode
parameter to determine whether the request for a list of tasks or a single task object. Also note that the XSL transform uses the XSLTdocument()
function to access the contents of the stored objects in the file system.
The get_response_html.xsl
document controls the output of GET requests sent by clients that accept the
text/html
content type. This transform (placed in the Documents folder)
is a bit more involved than the transform for the XML content type. In this case,
the transform needs to return valid XHTML that contains not only the list of tasks,
but also an HTML FORM that can be used to POST new task objects to the server.
Notice that the checked-in version of the transform includes added markup for CSS and Javascript files as well as additional content for the live demo. These items are not essential for the transform and are included as part of this example to complete the online demo.
The last XSL transform needed for this example is the post_request_form.xsl document. This transform converts the incoming values POSTed from the HTML form into a valid task object for storage on the disk. This document assumes that all values posted form an HTML form will be supplied as an XML document in the following format:
<form> <name1>value1</name1> <name2>value2</name2> ... </form>
This process of converting the urlencoded body of the HTML form POST into an XML document is automatically handled by the exyus engine.top
Along with XSL transforms, the
XmlFileResource
class uses XSD Schema documents to validate incoming documents. In the previous section you learned
that the exyus engine automatically converts POSTed
HTML form values into a valid XML document (with the root of form
). Other typical
content types (XML, Atom, RDF) can also post valid XML documents. In this section, you'll learn
how to create and save XSD Schema documents that can be used at runtime.
Like the naming pattern for XSL transforms, exyus expects XSD documents to follow a standard pattern that includes:
For example, the XSD document that will be used to validate data sent to the server using the
HTTP PUT method with a content-type header of text/xml
will be named:
put_xml.xsd
. Similarly, the document for data sent using an HTML FORM POST will be
named: post_form.xsd
. So, the pattern for naming XSD validators is
[method]_[type].xsd
. As with XSL transform documents, all validators need to be
placed in the Documents folder for the resource class.
The actual content-type for HTML FORM POST isapplication/x-www-form-urlencoded
. However, the XSD filename pattern uses "form." The exyus engine uses a configuration file (config/media-types.xml
) to associate content-types with a file keyword. Adding support for a new content-type is easy. You just need to make a new entry in theconfig/media-types.xml
and start using that keyword for your XSL and XSD documents.
This example application supports both POST and PUT for the text/xml
content type.
That means two documents are needed: post_xml.xsd and
put_xml.xsd. The validators
will automatically be called when clients send data to the server via then PUT and POST methods. If
the contents of the HTTP body is invalid, an error will be returned. You can view an example of
an invalid POST online.
The final step in completing this example web application is adding some client scripting and CSS styles to the HTML representation of the task list. These are only referenced for the HTML version since the XML content-types do not need them.
In this example, client script is needed for the HTML version to handle the "update" and "delete" actions for the user interface. The "add" action is handled by the FORM POST and requires no script. However, this script also performs a client-side validation of the inputs before completing the POST. The update and delete actions are handled using the XmlHttpRequest object (Ajax scripting) library.
There are only a few 'interesting' methods in the tasklist.js file. They are:
You can view the complete tasklist.js file
online. Note the use of the ajax.httpHead()
method to retrieve the ETag
header of an item before attempting to update it. This prevents other user's edits from overwriting
the current update.
The final step is to add CSS styles to the HTML document to improve the 'look and feel' of the application. Unlike the javascript file, which is required to complete the functionality of this web app, none of the styles are needed to operate the application - they just enhance the user experience. You can view the contents of the tasklist.css file online.
If you are using a browser that allows you to turn CSS styles off (Opera, Firefox, etc.), you can test the online version of the TaskList application. both with and without the CSS styles.top
In this article, you learned how to use the exyus engine to build HTTP applications that comply with REST constraints. You learned how to create an "action matrix" to detail the client-server interactions and how to use the base classes in the exyus engine to create C# classes that include all the important details from the action matrix including the UriPatterns, MediaTypes, and which HTTP methods are supported. The use of XSL transforms and XSD schema documents to support processing both incoming requests and outgoing responses was also covered. Finally, you go to see how you can add code-on-demand using javascript and CSS styles to the HTML responses of the HTTP resource.
The aim of this article was to illustrate the power and flexibility of HTTP programming with REST constraints as well as how you can use the exyus engine to implement HTTP/REST with relative ease. Hopefully, this small example will encourage you to use HTTP/REST and exyus when building your future web applications.
topMike Amundsen lives and works as a contract programmer in Kentucky, USA. He currently spends most of his time creating and supporting large-scale web sites running under Windows and ASP.NET. In the past, he spent quite a bit of time as a trainer/speaker and was involved in the writing of several books on programming with Microsoft technologies.