defining views for exyus resource objects

this is one of a series of short articles that describe how basic HTTP programming works with the exyus engine for C#. the aim of the exyus engine is to make it as easy as reasonably possible to create REST-compliant web applications using C# and ASP.NET.

this article focuses on how to define client views against an exyus resource object. in this example, i have been working with a simple products/categories data model that shows how to implement a very basic shopping web. in other posts on this topic, i've talked about how resource object are defined and how to implement them using the exyus classes in C#. now, let's do a quick review and move on to executing the views of a resource.

defining the resource

the first step is to define the resource you plan on presenting to clients. in this case, i created a simple product resource that has the following XSD Schema definition:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="product">
    <xs:complexType>
      <xs:all>
        <xs:element name="id" type="xs:integer"  minOccurs="1" maxOccurs="1"/>
        <xs:element name="name" type="xs:string" minOccurs="1" maxOccurs ="1"/>
        <xs:element name="category" type="xs:string" minOccurs="1" maxOccurs ="1" />
        <xs:element name="quantity-per-unit" type="xs:integer" minOccurs="0" maxOccurs ="1" default="1"/>
        <xs:element name="unit-price" type="xs:float" minOccurs="0" maxOccurs ="1" default="10.00"/>
        <xs:element name="units-in-stock" type="xs:integer" minOccurs="0" maxOccurs ="1" default="100"/>
        <xs:element name="description" type="xs:string" minOccurs="0" maxOccurs ="1"/>
      </xs:all>
    </xs:complexType>
  </xs:element>
</xs:schema>

implement the resource object in C#

the next step is to create a code class in exyus that will define the product resource as a valid HTTP resource object. that means establishing the 1) address (/data/products/), verbs (GET [for now]), and the representations (text/html,text/xml). below is the exyus resource object:

[UriPattern(@"/data/products/(?<pid>[^/?]*)(?:\?)?(?:[^/]*)?")]
[MediaTypes("text/html", "text/xml")]
public class productsResource : XmlFileResource
{
    public productsResource()
    {
        this.ContentType = "text/html";
        this.DocumentsFolder = "~/documents/products/";
        this.StorageFolder = "~/storage/products/";
        this.XHtmlNodes = new string[] { "//description" };
        this.LocalMaxAge = 600;
        this.ImmediateCacheUriTemplates = new string[]
            {
                "/data/products/",
                "/data/products/{pid}"
            };
    }
}

implement the representations in XSLT

now you get to the current fun - implementing the response representations. in this example, i chose to make XHTML the default representation. that means i need to define a get_response_list_html.xsl document (see figure 1). here's what that looks like:

<?xml version='1.0' encoding='utf-16' ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" encoding="utf-16" omit-xml-declaration="no"/>

  <!-- root -->
  <xsl:template match="root">
    <div class="products">
      <xsl:apply-templates select="item" />
    </div>
  </xsl:template>

  <!-- unfiltered list -->
  <xsl:template match="item">
    <div class="product" seq="{position()}">
      <h3 class="name">
        <label for="id">name:</label>
        <a href="{document(./@dref)/product/name}" title="{document(./@dref)/product/name}">
          <xsl:value-of select="document(./@dref)/product/name" />
        </a>
      </h3>
      <p class="product-image">
        <a href="{document(./@dref)/product/name}" title="{document(./@dref)/product/name}">
          <img src="/xcs/products/images/{document(./@dref)/product/name}_thumb.jpg" />
        </a>
      </p>
      <p class="id">
        <label for="id">id:</label>
        <xsl:value-of select="document(./@dref)/product/id" />
      </p>
      <p class="category-detail">
        <label for="category">category detail:</label>
        <a href="categories/{document(./@dref)/product/category}" title="{document(./@dref)/product/category}">
          <xsl:value-of select="document(./@dref)/product/category"/>
        </a>
      </p>
      <p class="unit-price">
        <label for="unit-price">unit-price:</label>
        <xsl:value-of select="document(./@dref)/product/unit-price" />
      </p>
      <p class="units-in-stock">
        <label for="units-in-stock">units-in-stock:</label>
        <xsl:value-of select="document(./@dref)/product/units-in-stock" />
      </p>
      <p class="quantity-per-unit">
        <label for="quantity-per-unit">quantity-per-unit:</label>
        <xsl:value-of select="document(./@dref)/product/quantity-per-unit" />
      </p>
      <p class="description">
        <label for="description">description:</label>
        <xsl:value-of select="document(./@dref)/product/description" />
      </p>
    </div>
  </xsl:template>

</xsl:stylesheet>

i also need to implement the get_response_item_html.xsl document to handle requests for a single product. for brevity, i'll leave that one out for now (see figure 2).

note that i've also included hyperlinks in the list and item representations that point to other products and even category objects (not defined here, for brevity). this is a key point. defining hyperlinks is what good REST implementation is all about. that gives the client/user additional ways to 'discover' resources on the web.

other representations

since i defined this resource object to support both XHTML and XML media types, clients (browsers) can use the Accepts HTTP Header to tell the server which representation (XHTML or XML) the client wishes to recieve. this is another key REST constraint and is easily accomplished with exyus resource classes. since XML is the default media type for XmlFileResource objects, i do not need to do anything in order to support XML representations. exyus will send default XML representations for me. however, if i wish, i can override the default transformation with one of my own. i'll leave that for another time (see figure 3).

summary

so that's all it takes to define a resource and implement it using the exyus engine. the steps are simple and, for the most part trivial:

  1. decide on a resource object (use XSD Schema)
  2. decide on a resource address (use regular expressions)
  3. select one or more supported media types for represetations (text/html, text/xml, etc.)
  4. code your selections using an exyus resource class (in this case, XmlFileResource)
  5. as needed, implement response transforms (using XSLT) for your resource for each media type

this example focuses on the read-only (GET) version of the resource. in the next post on this topic, i'll show how easy it is to implement a read/write version of the product resource. without writing any C# code at all.