Safari Books Online is a digital library providing on-demand subscription access to thousands of learning resources.
The aim of this example is to illustrate the process of designing hypermedia types using HTML5 as the base format. Unlike the previous examples, which were based on XML and JSON (both formats devoid of native hypermedia controls), this example starts with a format that already supports basic hypermedia factors.
Starting with HTML5 provides both advantages and drawbacks when designing a hypermedia solution. The good news is the details of document design (which elements are valid, etc.), the specific hypermedia controls, and the method of expressing state transitions are already decided. This means designers do not need to worry about how to define and document much of the hypermedia type. However, with so many details already decided, there is less room for expressing the problem domain in ways clients can easily understand.
This duality of well-defined hypermedia controls and a limit on the options for expressing the problem domain is the key challenge behind working with existing hypermedia types and is, in part, the reason so few new APIs use HTML5 as the base. For many, it seems easier to start from zero using a non-hypermedia type such as XML or JSON and create all of the details from the beginning. But sometimes this option is not available to designers. Instead, designers often must be sure their implementations work well with existing clients (e.g. web browsers) with little or no support from custom scripting or other client-side plug-ins.
In cases where the design needs to rely on existing hypermedia
types like HTML5, a different approach is needed to express domain
semantics. Instead of creating new elements (as in XML) or objects (as
in JSON), domain semantics must be expressed using existing HTML5
elements (<article>, <section>,
<p>, <span>, etc.). Instead of
creating new state transition and process flow elements, designers need
to use those already available in HTML5 (<form>,
<input>, <a>, etc.).
However, it is still important to know the semantic value (the
meaning in relation to the problem domain) of each of these
already-defined elements. Instead of creating an
<email> element or <update-user>
transition block, designers need to use existing features of HTML5 to
add semantic meaning to the representations. The way to do this is to
use key HTML5 attributes to decorate the existing elements. These
attributes are:
idUsed to identify a unique data element/block within the representation
nameUsed to identify a state transition element (i.e. input) within the representation
classUsed to identify a non-unique data element/block within the representation
relUsed to identify a non-unique process flow element within the representation
The id attribute can be applied to any element in the
document, is a single string value (no spaces allowed), and must be
unique in a document:
<span id="invoice-001">...</span>
The name attribute is also a single string value
(without spaces). It can be assigned to a limited set of elements (those
associated with input), and multiple elements within the same document
can share the same value:
<label>Enter first invioce:</label><input name="invoice">...</input> <label>Enter second invoice:</label><input name="invoice">...</input>
The class attribute can be applied to any element in
the document, can appear on several elements within the document, and
allows multiple values to be applied as long as they are separated by a
space. This makes it possible to mark several document elements with the
same value as well as mark the same element with several values:
<span class="important invoice overdue">...</span> <span class="invoice pending">...</span>
The rel attribute has features of both the
class and name attributes. Like the
name attribute, a rel can only appear on a
limited set of elements (those associated with links) and need not be
unique within the document. Also, like the class attribute,
the rel supports multiple strings separated by
spaces:
<a href="..." rel="invoice">...</a> <a href="..." rel="invoice overdue">...</a>
Through the proper application of these four attributes to a wide range of existing HTML5 elements, it is possible to adequately express any problem domain details within a hypermedia type design. It is worth noting that each of the above attributes has slightly different rules in HTML5.
Just as in other base formats, a key step in implementing a hypermedia design using HTML5 is the process of identifying the needed state transitions. As has already been stated above, this example implements the basic features of a microblogging application. Below is a set of states that need to be represented:
The list of users
A single user
The list of messages
A single message
The list of possible queries (search users, view the user’s list of followers, etc.)
A template for creating a new user
A template for updating an existing user
A template for following an existing user
A template for searching for existing users
A template for adding a new message
A template for replying to an existing message
A template for searching for existing messages
As may be evident to the reader at this point, the above list
identifies three unique block types within a representation (users,
messages, queries) and seven transition blocks (create user, update
user, follow user, search user, add message, reply to a message, and
search messages). The unique blocks can be expressed using HTML5’s
<div> element and the transition blocks can be
expressed using the <form> element. Each of these
blocks will have a number of child elements.
The usual error representation has been left out of this design to save time and reduce repetition of the same material. When creating a complete design for production use, you should always include an error representation.
The details of these element blocks can easily be expressed in short HTML5 examples. These examples will serve as reference material when creating the application profile later in this chapter (see The Microblog Application Profile).
This example identifies three main types of content that may
appear within a representation: users, messages, and queries. These
can be expressed as HTML5 <div> elements with
unordered lists (<ul>, <li>) and
other child elements. Below are examples of each of the three main
content blocks.
There are two ways to represent users within this design: as a list of users and as a single user.
The list of users is represented using an HTML5 unordered list:
<!-- representing a list of users -->
<div id="users">
<ul class="all">
<li>
<span class="user-text">User1</span>
<a rel="user" href="..." title="profile for User1">profile</a>
<a rel="messages" href="..." title="messages by User1">messages</a>
</li>
...
<li>
<span class="user-text">UserN</span>
<a rel="user" href="..." title="profile for UserN">profile</a>
<a rel="messages" href="..." title="messages by UserN">messages</a>
</li>
</ul>
</div>
A single user is represented in a similar way:
<!-- representing a single user -->
<div id="users">
<ul class="single">
<li>
<img class="user-image" src="..." alt="image of User1"/>
<a rel="user" href="..." title="profile for User1">
<span class="user-text">User One</span>
</a>
<span class="description">
I am known to all as User One
</span>
<a rel="website" href="..." title="website">
User1's web site
</a>
<a rel="messages" href="..." title="messages by User1">messages</a>
</li>
</ul>
</div>
Messages can also be represented in two ways (as a list and as a single message).
Here is the list representation:
<!-- representing a list of messages -->
<div id="messages">
<ul class="all">
<li>
<span class="message-text">
this is a message
</span>
@
<a rel="message" href="..." title="message">
<span class="date-time">
2011-08-17 04:04:09
</span>
</a>
by
<a rel="user" href="..." title="User1">
<span class="user-text">User1</span>
</a>
</li>
...
<li>
<span class="message-text">
this is also a message
</span>
@
<a rel="message" href="..." title="message">
<span class="date-time">
2011-08-17 04:10:13
</span>
</a>
by
<a rel="user" href="..." title="UserN">
<span class="user-text">UserN</span>
</a>
</li>
</ul>
</div>
And here is the way a single message is represented:
<!-- representing a single message -->
<div id="messages">
<ul class="single">
<li>
<span class="message-text">
This is a message
</span>
<span class="single">@</span>
<a rel="message" href="..." title="message">
<span class="date-time">
2011-08-17 04:04:09
</span>
</a>
<span class="single">by</span>
<a rel="user" href="..." title="User1">
<span class="user-text">User1</span>
</a>
</li>
</ul>
</div>
This design uses a small set of simple queries. These are just links that return the list of messages, users, or the registration page:
<!-- representing the queries list -->
<div id="queries">
<ul>
<li><a rel="messages-all index" href="..." title="Home page">Home</a></li>
<li><a rel="users-all" href="..." title="User List">Users</a></li>
<li><a rel="register" href="..." title="Register">Register</a></li>
</ul>
</div>
Note that the first link in the list has two values for the
rel attribute.
This example identifies seven client-initiated state transfers.
Each of them can be expressed as HTML5 <form>
elements with <input> child elements. Below are
each of the transfer blocks along with the details for each child
element.
The server will include this block in the representation to allow clients to create a new microblog user:
<!-- state transfer for adding a new user --> <form method="post" action="..." class="user-add"> <input type="text" name="name" value="" required="true"/> <input type="text" name="email" value="" required="true"/> <input type="password" name="password" value="" required="true" /> <textarea name="description"></textarea> <input type="file" name="avatar" value="" /> <input type="text" name="website" value="" /> <input type="submit" value="Send" /> </form>
Notice that some fields are grouped under the SHOULD keyword and others are under the MAY keyword. These are just comments to indicate which fields “should” be returned by the server and which ones “may” be returned by the server. These annotations will be used later when writing up the documentation.
Once a user has been created, it should be possible to update that user account:
<!-- state transfer for updating an existing user --> <form method="post" action="..." class="user-update"> <input type="text" name="name" value="" required="true"/> <input type="text" name="email" value="" required="true"/> <input type="password" name="password" value="" required="true"/> <textarea name="description"></textarea> <input type="file" name="avatar" value="" /> <input type="text" name="website" value="" /> <input type="submit" value="Send" /> </form>
It is likely that update transitions will be prepopulated with
existing data. It is also possible that one or more of the
<input /> elements will be marked as read-only by
the server. These details will be left up to each server
implementation to determine.
Following a user is as simple as sending the identifier of the user you wish to follow:
<!-- state transition to follow an existing user --> <form method="post" action="..." class="user-follow"> <input type="text" name="user" value="" required="true"/> <input type="submit" value="Send" /> </form>
You may notice that there is nothing in the above transition to indicate the current user that wants to follow the identity in the user input element. For all of the transition examples shown here, the server is assumed to be able to know (when it is important) the identity of the current (or logged-in) user. This can be done via information in the action URI or via control data (HTTP Headers) such as the Authorization header or the Cookie header (see Current user and state data for details).
Here is the transition block for searching for users:
<!-- state transfer for searching users --> <form method="get" action="..." class="user-search"> <input type="text" name="search" value="..." required="true"/> <input type="submit" value="Send" /> </form>
Since this is a search action, the method attribute is set to GET, not POST.
Adding a new message is also a simple state transfer:
<!-- state transfer for adding a message --> <form method="post" action="..." class="message-post"> <textarea name="message" requried="true"></textarea> <input type="submit" value="Send" /> </form>
Replying to an existing message involves sending both the original user identifier and any reply text, which may include the original message text, to the server:
<!-- state transfer for replying to a message --> <form method="post" action="..." class="message-reply"> <input type="hidden" name="user" value="..." requried="true"/> <textarea name="message"></textarea> <input type="submit" value="Send" /> </form>
Since the point of this chapter is to cover implementation details when using HTML5, the remaining standard design elements have already been decided. However, it is still valuable to go over each of them here.
Using HTML5 as the base format means that the State Transfer style will be ad hoc. HTML5 Forms will be used to make all client-imitated transfers via GET (read-only) or POST (add/update). Even though the ad hoc style is used in HTML5, designers can still establish required and optional inputs in their hypermedia design. In this example, the design uses both.
The domain style of HTML5 is agnostic. The element and attribute
names are all independent of any domain semantics. However, as mentioned
earlier in this chapter (see Expressing Application Domain Semantics in HTML5), HTML5 supports domain
semantic expression using common attribute values (id,
name, class). Finally, the Application Flow
style for HTML5 is applied via values for the rel attribute
on href tags.
Usually hypermedia designs use the rel attribute
(or its equivalent in the data format) to mark all state transitions,
including ones that require arguments. However, HTML5 does not support
the rel attribute on the form element. For
this reason, transitions that require arguments (e.g. forms) will be
marked with a class attribute instead.
Although HTML5 is a domain-agnostic base format, the built-in
state transfer and application flow elements make most of the design
details very easy. The only creative work that needs to be done is
arranging existing HTML5 elements (article,
section, div, p,
span, etc.) and decorating them with the necessary
attributes (id, name, class,
rel).
The application of these attribute decorations is covered in the next section.
Since HTML5 is a domain-agnostic media type, all domain-specific
information (both the data elements and the transition details) needs to
be specified as additional information in each representation. As has
already been pointed out earlier in this chapter (see Expressing Application Domain Semantics in HTML5), in HTML5 you can
express domain-specific information using a set of attributes
(id, name, class, and
rel).
Also, this implementation will require users to log in before posting new messages. That means the implementation will need to be able to identify the current logged-in user.
This example implementation will rely on HTTP’s Authorization header to identify the currently logged-in user. That means this example server will use HTTP Basic Authentication for selected state transitions (Update a User, Follow a User, Add a New Message, and Reply to a Message). It is important to point out that user identification is not specified in the media type design; it is an implementation detail left to servers and clients to work out themselves.
The decision to leave user authentication independent of the
media type has a number of advantages. First, this allows clients and
servers to negotiate for an appropriate authentication scheme at
runtime (the HTTP WWW-Authenticate head is used to
advertise supported authentication schemes). Second, leaving it out of
the media type means that servers are free to establish and transition
details on their own. For example, Open Auth (OAuth) has a set of
requirements for interacting with more than one web server in order to
complete authentication. Finally, leaving authentication details out
of the media type design allows servers to take advantage of whatever
means may become available in the future.
This design relies on three unique identifiers for representations:
Applied to a div tag. The list of messages in
this representation. This list may contain only one
message.
Applied to a div tag. The list of valid
queries in this representation. This is a list of simple queries
(represented by the HTML anchor tag).
Applied to a div tag. The list of users in
this representation. This list may contain only one user.
There are a number of class attributes that can
appear within a representation. Clients should be prepared to
recognize the following values:
Applied to a UL tag. A list representation.
When this element is a descendant of
DIV.id="messages" it MAY have one or more
LI.class="message" descendant elements. When this
element is a descendant of DIV.id="users" it MAY
have one or more LI.class="user" descendant
elements.
Applied to a SPAN tag. Contains the UTC
date-time the message was posted. When present, it SHOULD be
valid per RFC3339.
Applied to a SPAN tag. Contains the text
description of a user.
Applied to a UL tag. A list representation.
When this element is a descendant of
DIV.id="messages it contains the
list of messages posted by the designated user’s friends and
MAY have one or more "LI.class="message"
descendant elements. When this element is a descendant of
DIV.id="users" it contains the list of users who
are the friends of the designated user and MAY have one or
more LI.class="user" descendant elements.
Applied to a UL tag. A list representation
of all the users from the designated user’s friends list. MAY
have one or more LI.class="user" descendant
elements.
Applied to a UL tag. When this element is a
descendant of DIV.id="messages" it contains the
list of messages posted by the designated user and MAY have
one or more LI.class="message" descendant
elements. When this element is a descendant of
DIV.id="users" it SHOULD contain a single
descendant LI.class="user" with the designated
user’s profile.
Applied to a UL tag. A list representation
of all the messages that mention the designated user. It MAY
contain one or more LI.class="message" descendant
elements.
Applied to an LI tag. A representation of a
single message. It SHOULD contain the following descendant
elements:
SPAN.class="user-text" |
A.rel="user" |
SPAN.class="message-text" |
A.rel="message" |
It MAY also contain the following descendant elements:
IMG.class="user-image" |
SPAN.class="date-time" |
Applied to a FORM tag. A link template to
add a new message to the system by the designated (logged-in)
user. The element MUST be set to
FORM.method="post" and SHOULD contain a
descendant element:
TEXTAREA.name="message" |
Applied to a FORM tag. A link template to
reply to an existing message. The element MUST be set to
FORM.method="post" and SHOULD contain the
following descendant elements:
INPUT[hidden].name="user" (the author
of the original post) |
TEXTAREA.name="message" |
When this element is a descendant of
DIV.id="messages" it contains the message
selected via a message link. SHOULD have a single
LI.class="message" descendant element. When this
element is a descendant of DIV.id="users" it
contains the user selected via a user link. SHOULD have a
single LI.class="user" descendant element.
Applied to a FORM tag. A link template to
search of all the messages. The element MUST be set to
FORM.method="get" and SHOULD contain the
following descendant elements:
INPUT[text].name="search" |
Applied to a SPAN tag. The text of a
message posted by a user.
Applied to a UL tag. A list representation.
When this element is a descendant of
DIV.id="messages" it contains a list of messages
and MAY have one or more LI.class="message"
descendant elements. When this element is a descendant of
DIV.id="users" it contains a list of users and
MAY have one or more LI.class="user" descendant
elements.
Applied to a UL tag. A list representation
of all the messages posted by the designated user that were
shared by other users. It MAY contain one or more
LI.class="message" descendant elements.
Applied to an LI tag. A representation of a
single user. It SHOULD contain the following descendant
elements:
SPAN.class="user-text" |
A.rel="user" |
A.rel="messages" |
It MAY also contain the following descendant elements:
SPAN.class="description" |
IMG.class="avatar" |
A.rel="website" |
Applied to a FORM tag. A link template to
create a new user profile. The element MUST be set to
FORM.method="post" and SHOULD contain the
following descendant elements:
INPUT[text].name="user" |
INPUT[text].name="email" |
INPUT[password].name="password" |
It MAY also contain the following descendant elements:
TEXTAREA.name="description" |
INPUT[file].name="avatar" |
INPUT[text].name="website" |
Applied to a FORM tag. A link template to
add a user to the designated user’s friend list. The element
MUST be set to FORM.method="post" and SHOULD
contain the descendant element:
INPUT[text].name="user" |
Applied to an IMG tag. A reference to an
image of the designated user.
Applied to a SPAN tag. The user nickname
text.
Applied to a FORM tag. A link template to
update the designated user’s profile. The element MUST be set
to FORM.method="post" and SHOULD contain the
following descendant elements:
INPUT[hidden].name="user" |
INPUT[hidden].name="email" |
INPUT[password].name="password" |
It MAY also contain the following descendant elements:
TEXTAREA.name="description" |
INPUT[file].name="avatar" |
INPUT[text].name="website" |
Applied to a FORM tag. A link template to
search of all the users. The element MUST be set to
FORM.method="get" and SHOULD contain the
descendant element:
INPUT[text].name="search" |
HTML5 uses the name attribute to identify a
representation element that will be used to supply data to the server
during a state transition. Clients should be prepared to supply values
for the following state transition elements:
Applied to a TEXTAREA element. The description of the user.
Applied to an INPUT[text] or INPUT[hidden] element. The email address of a user. When supplied, it SHOULD be valid per RFC5322.
Applied to a TEXTAREA element. The message to post (for the designated user).
Applied to an INPUT[text] element. The (full) name of a user.
Applied to an INPUT[password] element. The password of the user login.
Applied to an INPUT[text]. The search value to use when
searching messages (when applied to
FORM.class="message-search") or when searching
users (when applied to
FORM.class="users-search").
Applied to an INPUT[text] or INPUT[hidden] element. The public nickname of a user.
Applied to an INPUT[file] element. The image for the user.
Applied to an INPUT[text]. The URL of a website associated with the user profile. When supplied, it SHOULD be valid per RFC 3986.
This design also identifies a number of possible simple state
transitions, or static links, that may appear within representations.
These will appear as HTML anchor tags with the following
rel attribute values:
Applied to an A tag. A reference to the starting URI for the application.
Applied to an A tag. A reference to a message representation.
Applied to an A tag. A reference to the message-post FORM.
Applied to an A tag. A reference to the message-reply FORM.
Applied to an A tag. A reference to the message-share FORM.
Applied to an A tag. A reference to a list representation of all the messages in the system.
Applied to an A tag. A reference to the messages-search FORM.
Applied to an A tag. A reference to a user representation.
Applied to an A tag. A reference to the user-add FORM.
Applied to an A tag. A reference to the user-follow FORM.
Applied to an A tag. A reference to the user-update FORM.
Applied to an A tag. A reference to a list representation of all the users in the system.
Applied to an A tag. A reference to list representation of the designated user’s friend users.
Applied to an A tag. A reference to list representation of the users who follow the designated user.
Applied to an A tag. A reference to the users-search FORM.
Applied to an A tag. A reference to the website associated with a user.