How to cite this paper
Robie, Jonathan, Rob Cavicchio, Rémon Sinnema and Erik Wilde. “RESTful Service Description Language (RSDL): Describing RESTful Services Without Tight
Coupling.” Presented at Balisage: The Markup Conference 2013, Montréal, Canada, August 6 - 9, 2013. In Proceedings of Balisage: The Markup Conference 2013. Balisage Series on Markup Technologies, vol. 10 (2013). https://doi.org/10.4242/BalisageVol10.Robie01.
Balisage: The Markup Conference 2013
August 6 - 9, 2013
Balisage Paper: RESTful Service Description Language (RSDL)
Describing RESTful Services Without Tight Coupling
Jonathan Robie
Jonathan Robie is an architect and chair of the IIG REST Governance Board at EMC
Corporation, an editor of JSONiq, a query language for JSON and XML, and the lead
editor
of the W3C XQuery and XPath specifications. Before joining EMC, Jonathan worked on
the
Apache Qpid implementation of AMQP for Red Hat, was the Program Manager for DataDirect
XQuery, and worked on the architectural team for three XML databases: Software AG's
Tamino, Texcel, and POET's CMS. He received an Infoworld Innovator 2005 award for
his work
on XQuery.
Rob Cavicchio
Rob Cavicchio is an Information Architect at EMC. He designs technical documentation,
and implements and supports tools that enable efficient documentation management.
He has
worked in the technical writing field since 1994.
Rémon Sinnema
Rémon Sinnema is a developer and Security Champion at EMC Corporation, member of the
IIG REST Governance Board at EMC Corporation, member of the OASIS XACML Technical
Committee, and lead editor of the XACML REST Profile.
Erik Wilde
Erik Wilde works as an architect at EMC's Information Intelligence Group (IIG). He
is
a self-proclaimed Web Plumber and Ecosystem Gardener, and has spent the majority of
the
last several years working on issues around service architectures, SOA, REST, and
other
questions of open service systems. Before joining EMC, Erik worked at UC Berkeley's
School
of Information, where he focused on questions around open data and open services,
and
taught courses about Web Architecture and XML. Erik is a native of Berlin, Germany,
and
received his Ph.D. from ETH Zürich in Switzerland.
Except where otherwise noted, this content is licensed under a Creative Commons Attribution
3.0 License. Schemas and stylesheets in this document are licensed under an Apache
2.0 License.
Abstract
RESTful Service Description Language (RSDL) is an XML vocabulary for designing and
documenting hypermedia-driven RESTful Services. RSDL takes a purist hypermedia-driven
approach to REST design, requiring that a service have a single entry point, and focusing
the design on resources, links, and media types.
Table of Contents
- Introduction
- What should a RESTful service description describe?
- A Sample RSDL Description
- The Structure of a RSDL Description
-
- Service
- Media Types
- Resources
- Link Relations
- Headers
- Authentication
- Status Codes
- URI Parameters
- Documentation Modules
- Initial Experience
- Future Work
- Conclusions
- Appendix A. RSDL Schema
- Appendix B. HTML module for RSDL Documentation
- Appendix C. DocBook module for RSDL Documentation
- Appendix D. An XSLT Stylesheet for RSDL
- Appendix E. RSDL Description for the Planets Service
Introduction
RESTful Service Description Language (RSDL) is an XML vocabulary for designing and
documenting hypermedia-driven RESTful Services. RSDL takes a purist hypermedia-driven
approach
to REST design, requiring that a service have a single entry point, and focusing the
design on
resources, links, and media types. By representing the concepts of REST in a formal
vocabulary, RSDL helps designers of an interface think more clearly about the design
process.
In our work at EMC Corporation, we teach and coach RESTful design, evaluate proposed
REST
interfaces for products and internal services, and produce documentation for these
interfaces.
We created RSDL to make our work more efficient, and we have begun using it as a teaching
tool, a standard format for specifications that allows us to track design changes
in source
code control, test for design consistency with specification-driven programs, and
produce
documentation.
The REST community has little consensus on how to document a RESTful service beyond
this
well-known Roy Fielding quote:
Any effort spent describing what methods to use on what URIs of interest should be
entirely defined within the scope of the processing rules for a media type (and, in
most
cases, already defined by existing media types). [Failure here implies that out-of-band
information is driving interaction instead of hypertext.]
While this gives excellent guidance about things that should not be documented,
it tells us that we should focus on documenting a media type without telling us how
to do so.
Well-designed RESTful services are loosely coupled, allowing a client to use the service
with
no prior knowledge beyond an initial URI and a set of media types. But this gives
little
concrete guidance to a person who is specifying a RESTful service, and needs to know
precisely
what information should be provided to a client, which fundamential concepts should
be
documented for a media type, how dependencies on multiple media types in a single
service
should be represented, where to document semantics specific to the application domain,
or how
to organize all of the information that belongs in a specification.
This paper presents RESTful Service Description Language (RSDL, pronounced "risdle"),
an
XML vocabulary that provides a structured way to specify a RESTful service. RSDL is
still
being developed.
What should a RESTful service description describe?
The description for a RESTful service should describe semantics specific to the service
that go beyond functionality known to a generic REST client. In RSDL, every RESTful
service
has a single entry point, which corresponds to a home resource, and all other resources
can be
discovered from the home resource using links. The structure of a RSDL description
enforces
these design constraints.
A RSDL description focuses on describing the following items:
-
Media types, with documentation and an optional link to a schema or description that
documents each media type used in a service. This includes the kinds of response bodies
sent by the server, and how to find links in them and identify specific kinds of
link.
-
Resources, designating one resource as the service entry point.
-
Links for each resource and the resources they refer to.
-
Methods allowed for each resource, and the associated requests and responses.
-
HTTP headers, including custom headers.
-
Authentication mechanisms and identity providers, which can be specified for the
entire service or at the individual resource level.
-
URI parameters and URI templates.
-
HTTP status codes, which are described at the service level (not at the individual
request level or the resource level), but can be referenced at the request level if
need
be.
It is important to clearly understand the relationship between services, resources,
links,
URIs, methods, representations, and media types. A RESTful service is a collection
of
resources, which are identified by URIs. To start using a service, a client needs
an entry
point. A service's published entry point is the URI of the home resource. All other
resources
should be discoverable from the home resource using links, which identify URIs that
refer to
other resources, and can be used for HTTP requests. A client can do a GET
to
obtain a representation of a resource in, say, XML or JSON. A representation is a
sequence of
bytes that represents the current state of a resource; the syntax and semantics of
a
representation are defined by the corresponding media type. Note that a representation
is not
the same thing as a resource, it is merely the data required to represent the resource's
state. You cannot send HTTP requests to a representation, you send HTTP requests to
a
resource. You cannot parse or generate a resource, you can parse or generate a representation.
These distinctions are important, and they are reflected in the structure of RSDL.
For
instance, a media type can provide schemas or descriptions that describe the structure
of its
representations. A resource describes the HTTP requests that can be applied to a resource.
In
RSDL, we view links as an abstraction that represents the potential relationship among
resources, they have a concrete representation in a given media type. If a given resource
has
both an XML representation and a JSON representation, the same links will be represented
in
different ways by the two media types.
In addition to information that is provided for the benefit of REST clients, some
other
aspects of a REST design should be specified in a structured way simply for the purpose
of
fostering consistent design in the implementation. The design and structure of URIs
is a
particularly important example of this—clients should treat URIs as opaque, but server-side
implementations need to understand the URIs they respond to, and URIs often contain
metadata
that is useful for someone who is learning an API interactively, so consistent structure
in
URIs is important. The purist side of us would like to leave the structure of URIs
completely
out of the specification, but in practice, the URI formats often link the specification
to the
actual implementation. RSDL allow the structure of a URI to be specified, and variable
portions of a URI can be specified using a URI template (URI Templates). Our
documentation stylesheets omit the URI structure in client API documentation for all
resources
except the home resource.
This information is highly structured, with many cross references and semantic
constraints, but it is typically documented in formats like HTML, Wiki pages, or word
processing documents, which offer no aid in getting the structure right. And although
this
information is often reused in many different ways, it is not generally created in
formats
that foster reuse. Beyond that, an XML representation of a RESTful web service is
extremely
useful for teaching RESTful service design, creating and maintain designs over time
alongside
implementation code, guiding the process of design, visualizing and evaluating service
designs
created by others, generating various forms of human and machine-readable documentation,
providing data for testing clients, and generating stubs for server-side code. The
structure
of RSDL's schema can guide the design process, nudging designs to be more RESTful.
A RESTful service typically needs to document additional information beyond normal
HTTP
semantics. RSDL allows the following to be documented either in schemas or documentation
associated with a mediatype, or in documentation elements, which allow documentation
to be
written in HTML, DocBook, or other formats, and can be placed throughout a RSDL description.
This information includes:
-
Application semantics that are orthogonal to REST per se. This is information that
is
completely unknown to a generic REST client, but this information largely defines
what the
application is all about. This includes the application semantics of most XML elements
or
JSON properties. For instance, in Atom, these semantics include the meaning of container
elements like feeds, entries, and content, and metadata elements like author, category,
and contributor, etc. In the HTML media type, these semantics include all intended
browser
behavior implied by the data that does not involve the use of links.
-
Protocol semantics added by a particular media type. For instance, the Atom Publishing
Protocol specifies that a POST to a collection URI adds a new member to a collection,
a
side-effect that would be difficult for a generic client to discover if it had no
knowledge of the media type.
The best-known description language for REST is WADL. WADL provides a
detailed, well-structured description of a REST interface, but the structure of WADL
is driven
by URI patterns and server-side implementation concerns rather than hypermedia-driven
design.
WADL has been criticized for inviting URI-based tight coupling between the client
and the
server, so that changes to server-side code can break existing clients. From a REST
perspective, the main problem with WADL is that it exposes interfaces using static
metadata,
instead of describing conventions for discovering and using links, and even provides
tools to
create stub code for clients and servers from the WADL description, code that is guaranteed
to
rely on this static metadata. WADL directly exposes URIs and fixed paths instead of
relying on
links, documents specific errors instead of relying on generic HTTP processing, and
does not
distinguish information needed to specify the server from information provided to
the client
interface.
In many ways, RSDL is similar to WADL, with a great deal of overlap in the information
that is represented. But RSDL is designed for hypermedia-driven services. In RSDL,
every
service has a single published entry point, which corresponds to a home resource,
and all
other resources can be discovered from the home resource using links. Like WADL, RSDL
describes resources and relationships among resources, but RSDL always uses links
to describe
relationships. Like WADL, RSDL describes the methods that can be used for to a given
resource,
but RSDL does not describe expected error codes for each method; instead, it relies
on the use
of generic HTTP status codes; if specific semantics are required, e.g. to document
the use of
a redirect for authentication purposes, RSDL allows the semantics of a given status
code to be
documented globally for the service. Like WADL, RSDL allows schemas that describe
expected
formats for representations, but RSDL also allows descriptions in other formats, including
W3C
XML Schemas, Relax-NG, JSON Schema, HTML descriptions, text-based descriptions, or
anything
else that can be referred to with a URI.
A Sample RSDL Description
The following RSDL example describes a simple service that supports a collection of
documents. The service uses several media types: an XML Home document as the entry
point, an
atom feed to represent the collection of documents, an HTML description that describes
the
service, and a media type for the documents used in the service. The schema for RSDL
is
provided in an appendix. Documentation is embedded at
many points in the description, using a separate documentation module that is included.
The
appendixes provide documentation modules for HTML and
DocBook, this example uses the HTML
module.
The Documents Service
<?xml version="1.0" encoding="utf-8"?>
<service name="Documents"
identity-provider-ref="idp"
xmlns="http://identifiers.emc.com/rsdl"
xmlns:html="http://www.w3.org/1999/xhtml/">
<documentation>This RESTful service provides a simple ATOM feed that allows documents to be read,
created, modified, or deleted. </documentation>
<start ref="res-home"/>
<media-types>
<media-type id="med-document" name="application/vnd.example.document+xml">
<documentation> The media type for the service described by this RSDL description.</documentation>
<description href="example.com/mediatypes/documents.rnc" type="rnc"/>
</media-type>
<media-type id="med-home-xml" name="application/home+xml">
<documentation> Home Documents for HTTP Services: XML Syntax </documentation>
<description href="http://tools.ietf.org/html/draft-wilde-home-xml-01.html" type="html"/>
</media-type>
<media-type id="med-atom" name="application/atom+xml">
<documentation> Atom feeds, updateable using AtomPub conventions, with feed paging.
</documentation>
</media-type>
<media-type id="med-html" name="text/html">
<documentation> HTML documents. </documentation>
</media-type>
</media-types>
<resources>
<resource id="res-home" name="home">
<location uri="/"/>
<links>
<link link-relation-ref="rel-documents" resource-ref="res-documents"/>
<link link-relation-ref="rel-about" resource-ref="res-about"/>
</links>
<methods>
<method name="GET">
<response>
<representation media-type-ref="med-home-xml" entity="resources"/>
</response>
</method>
</methods>
</resource>
<resource id="res-documents" name="documents">
<location uri="/documents"/>
<links>
<link link-relation-ref="rel-self" resource-ref="res-documents"/>
<link link-relation-ref="rel-first" resource-ref="res-documents"/>
<link link-relation-ref="rel-next" resource-ref="res-documents"/>
<link link-relation-ref="rel-last" resource-ref="res-documents"/>
<link link-relation-ref="rel-previous" resource-ref="res-documents"/>
<link link-relation-ref="rel-alternate" resource-ref="res-document">
<documentation>
In an ATOM feed, we use the alternate link relation to indicate the member
type.
</documentation>
</link>
</links>
<methods>
<method name="GET">
<response>
<representation media-type-ref="med-atom" entity="atom:feed"/>
</response>
</method>
<method name="POST">
<request>
<documentation>Creates a document</documentation>
<representation media-type-ref="med-document" entity="document"/>
</request>
<response>
<documentation>Returns the newly created document</documentation>
<representation media-type-ref="med-document" entity="document"/>
</response>
</method>
</methods>
</resource>
<resource id="res-document" name="document">
<documentation> </documentation>
<location template="/document/{oid}">
<var name="oid">
<documentation> Identifier for the document. </documentation>
</var>
</location>
<links>
<link link-relation-ref="rel-self" resource-ref="res-document"/>
</links>
<methods>
<method name="GET">
<response>
<representation media-type-ref="med-document" entity="res-document"/>
</response>
</method>
<method name="PUT">
<request>
<representation media-type-ref="med-document" entity="res-document"/>
</request>
</method>
<method name="DELETE"/>
</methods>
</resource>
<resource id="res-about" name="about" public="true">
<documentation>An HTML page describing the service.</documentation>
<location uri="/about"/>
<methods>
<method name="GET">
<response>
<representation media-type-ref="med-html" entity="html"/>
</response>
</method>
</methods>
</resource>
</resources>
<link-relations>
<documentation> Link relations used in the media-type. IANA link relations can be found <ref
uri="http://www.iana.org/assignments/link-relations/link-relations.xml">here</ref>. Non-IANA
link relations will be registered on identifiers.example.com. </documentation>
<link-relation id="rel-about" name="about"/>
<link-relation id="rel-alternate" name="alternate"/>
<link-relation id="rel-self" name="self"/>
<link-relation id="rel-edit" name="edit"/>
<link-relation id="rel-first" name="first"/>
<link-relation id="rel-last" name="last"/>
<link-relation id="rel-next" name="next"/>
<link-relation id="rel-previous" name="previous"/>
<link-relation id="rel-parent" name="parent"/>
<link-relation id="rel-documents" name="identifiers.example.com/linkrel/documents"/>
</link-relations>
<headers>
<header id="hea-authenticate" name="WWW-Authenticate" type="request"/>
</headers>
<authentication>
<mechanism id="aut-http" name="HTTP Authentication" authentication-type="rfc2617">
<documentation>
We use HTTP Authentication as defined in <ref uri="http://tools.ietf.org/html/rfc2617">RFC 2617</ref>
with custom schemes. If an unauthenticated user tries to access a protected resource, a
<ref status-code="sta-unauthorized"/> status is returned, along with one or more
<ref header="hea-authenticate"/> headers, each of which contains an authentication
<html:em>challenge</html:em>. The challenges consist of a scheme followed by one or more parameters.
</documentation>
<scheme name="basic">
<parameter name="realm"/>
</scheme>
</mechanism>
<identity-provider id="idp" mechanism-ref="aut-http"/>
</authentication>
<status-codes>
<status id="sta-unauthorized" code="401">
<documentation> The request requires authentication. When this status code is returned, the
response contains one or more <ref header="hea-authenticate"/> headers that each contain an
<ref mechanism="aut-http">authentication challenge</ref>. </documentation>
</status>
</status-codes>
</service>
This example will be examined in more detail in the following section.
The Structure of a RSDL Description
In this section, we will explore the structure of a RSDL description, using the example
from the previous section.
Service
The top-level element for a RSDL description is the service element. Here is the
structure of the service element, in Relax-NG Compact syntax, together with the optional
attribute used to designate an identity provider for authentication, and a start element
that identifies the home resource.
start = service
service =
element service {
id?,
name,
identity-provider-ref?,
documentation?,
service-start,
media-types,
resources,
link-relations?,
headers?,
authentication?,
status-codes?,
uri-parameters?
}
service-start = element start { idref }
idref = attribute ref { xsd:IDREF }
identity-provider-ref = attribute identity-provider-ref { xsd:IDREF }
Consider the following fragment:
<service name="Documents"
identity-provider-ref="idp"
xmlns="http://identifiers.emc.com/rsdl"
xmlns:html="http://www.w3.org/1999/xhtml/">
<documentation> This RESTful service provides a simple ATOM feed that allows documents to be read,
created, modified, or deleted. </documentation>
<start ref="res-home"/>
!!! SNIP !!!
</service>
The name
of a service is provided primarily for human beings who need to
refer to the service. REST clients do not use a name to identify a service, they enter
a
service using the URI of the home resource.
The identity-provider-ref
attribute refers to an identity provider that can
be used to authenticate for the service. This attribute is an IDREF
that refers
to an identity provider in the authentication
element, which is discussed
later. If an identity provider is specified, all resources require authentication
by
default, unless declared public (this is described in the section on
resources
). If no identity provider is specified, resources do not require
authentication by default, but an individual resource can specify an identity
provider.
The start
element identifies the home resource, which is the published
entry point for the service. Because every RESTful service should have a single published
entry point, the start
element is required.
Media Types
In RSDL, media types describe the resource representations used in a REST service.
In
the systems we design, it is quite common for a service to use multiple media types;
for
instance, the example we are discussing is focused on documents, but it also uses
XML Home
Documents to provide a set of available links in the home resource, uses Atom and
AtomPub
with feeds to represent collections, and uses HTML to provide a human-readable description
of the service. The resource representations for a media type may be in XML, for which
there
are standard schema languages, but they may also use JSON or any other format, and
the
authoritative description for a given media type may be a document available in HTML,
text,
PDF, or some other format. Some media types are shared among multiple specifications,
other
media types have no authoritative description. Two media types may represent the same
properties in XML and JSON respectively. Because of this, media type descriptions
in RSDL
allow reference to any available schema or description in formats we use, but they
do not
require a schema or a description, and a media type can be documented directly in
its
documentation
element. Because some services need both XML and JSON
representations, we also allow RSDL descriptions to avoid duplication by specifying
properties in resources rather than in the media types, and documenting the manner
in which
properties are mapped to the corresponding +xml
or +json
media
types. This is described in the section on resources
.
The following schema fragment describes RSDL media types.
media-types = element media-types { documentation?, media-type* }
media-type = element media-type { id?, name, documentation?, description* }
media-type-ref = attribute media-type-ref { xsd:IDREF }
description = element description { type, href, documentation? }
type = attribute type { "rnc" | "rng" | "xsd" | "JSONSchema" | "sedola" | "text" | "html" }
href = attribute href { xsd:anyURI }
The type
attribute of a media type description refers to the language of
the document referred to by the href
attribute. It can be an XML schema (in
Relax-NG Compact Syntax (rnc
), Relax-NG (rng
), or W3C XML Schema
(xsd
), a JSON Schema (JSONSchema
), a human readable description
(in text
or html
), or Sedola (sedola
), an XML format
that provides a structured description of a media type with cross-references into
the
document that defines it.
Here are the media types for our example:
<media-types>
<media-type id="med-document" name="application/vnd.example.document+xml">
<documentation> The media type for the service described by this RSDL description.</documentation>
<description href="example.com/mediatypes/documents.rnc" type="rnc"/>
</media-type>
<media-type id="med-home-xml" name="application/home+xml">
<documentation> Home Documents for HTTP Services: XML Syntax </documentation>
<description href="http://tools.ietf.org/html/draft-wilde-home-xml-01.html" type="html"/>
</media-type>
<media-type id="med-atom" name="application/atom+xml">
<documentation> Atom feeds, updateable using AtomPub conventions, with feed paging.
</documentation>
</media-type>
<media-type id="med-html" name="text/html">
<documentation> HTML documents. </documentation>
</media-type>
</media-types>
Note that the media-type
for
application/vnd.example.document+xml
provides both inline documentation and a
schema, the media-type
for application/home+xml
provides inline
documentation and a reference to an HTML page, and the media-type
s for
application/atom+xml
and text/html
provide only brief inline
documentation.
Resources
Resources are at the heart of RSDL, which provides rich support for them. Here is
a
schema fragment for resources:
resources = element resources { id?, documentation?, resource* }
resource =
element resource {
documentation?,
id,
name,
identity-provider-ref?,
public?,
status?,
extends?,
location?,
properties?,
links?,
methods
}
name = attribute name { text }
public = attribute public { "true" }
status = implementation-status?, design-status?
implementation-status =
attribute implementation-status {
"future" | "assigned" | "poc" | "partial" | "complete" | "passed"
}
design-status =
attribute design-status { "future" | "assigned" | "poc" | "partial" | "complete" | "approved" }
# A resource can extend an existing resource definition, inheriting what it already defines.
extends = attribute extends { xsd:IDREF }
location = element location { documentation?, (uri | (uri-template, var*)) }
uri = attribute uri { xsd:anyURI }
uri-template = attribute template { xsd:string }
# uri-parameter-ref indicates that the value is supplied by the client, using a URI parameter.
# If no uri-parameter-ref is present, the value is supplied by the server.
var = element var { documentation?, id?, name, uri?, uri-parameter-ref? }
properties = element properties { documentation?, property* }
property = element property { id?, name, documentation? }
links = element links { documentation?, link* }
link = element link { link-relation-ref, resource-ref, status?, documentation? }
resource-ref = attribute resource-ref { xsd:IDREF }
link-relation-ref = attribute link-relation-ref { xsd:anyURI }
methods = element methods { method* }
method = element method { id?, method-name, status?, request?, response? }
method-name = attribute name { http-method }
request = element request { documentation?, request-uri-parameters?, header-refs?, representation* }
response =
element response { documentation?, response-status-codes?, header-refs?, representation* }
request-uri-parameters = element uri-parameters { request-uri-parameter }
request-uri-parameter = element uri-parameter { idref }
# When possible, avoid documenting status codes at the individual request level.
# If you have to, declare it globally and refer to it from the request.
response-status-codes =
element status-codes {
element status-code { ref }*
}
# When possible, avoid documenting headers at the individual request level.
# If you have to, declare it globally and refer to it from the request.
header-refs = element header-refs { documentation?, header-ref* }
header-ref = element header-ref { ref }
representation = element representation { documentation?, media-type-ref, entity? }
entity = attribute entity { text }
http-method = "GET" | "PUT" | "HEAD" | "POST" | "DELETE" | "TRACE" | "OPTIONS" | "CONNECT" | "PATCH"
Let's look at three resources from our example. The home resource for our example
is an
XML Home Document. In our own designs, we frequently use JSON Home Documents, or
XML Home Documents as the home document for a resource, but Atom feeds are also
popular as home documents, and some services use a single application-domain object
as the
home document. Here is the RSDL description of an XML Home Document resource:
<resource id="res-home" name="home">
<location uri="/"/>
<links>
<link link-relation-ref="rel-self" resource-ref="res-documents"/>
<link link-relation-ref="rel-documents" resource-ref="res-documents"/>
<link link-relation-ref="rel-about" resource-ref="res-about"/>
</links>
<methods>
<method name="GET">
<response>
<representation media-type-ref="med-home-xml" entity="resources"/>
</response>
</method>
</methods>
</resource>
In this example, the methods and the links define the interface for the resource.
Like
the name of a service, the name of a resource is not part of the interface. Neither
is the
id
, it exists to allow cross-reference in a RSDL description. Nor is the
location
element, which is optional.
A method specifies an HTTP method name that is supported for the resource in which
it
contains and the request
or response
associated with the method.
In the above example, a GET
method results in a response that contains the
representation of an XML Home Document, which was specified in the media types we
discussed
in an earlier section.
The links each define a transition to another resource. Each link contains a reference
to a globally declared link relation, discussed later, and the resource to which the
link
resolves. One link element is created for each (link-relation-ref
,
resource-ref
) pair. Note that RSDL allows links to be defined only in terms
of link relations, not in terms of the structure of URIs. A link refers to a resource,
not a
representation; to find the available representations for a resource, look at the
resource
and see what it returns for GET
. In this example, the second link contains a
reference to a globally declared link relation with the id rel-documents
, which
is defined as follows:
<link-relation id="rel-documents" name="identifiers.example.com/linkrel/documents"/>
It also contains a reference to the resource with the id res-documents
, an
Atom feed which is described below:
<resource id="res-documents" name="documents">
<location uri="/documents"/>
<links>
<link link-relation-ref="rel-self" resource-ref="res-documents"/>
<link link-relation-ref="rel-first" resource-ref="res-documents"/>
<link link-relation-ref="rel-next" resource-ref="res-documents"/>
<link link-relation-ref="rel-last" resource-ref="res-documents"/>
<link link-relation-ref="rel-previous" resource-ref="res-documents"/>
<link link-relation-ref="rel-alternate" resource-ref="res-document">
<documentation>
In an ATOM feed, we use the alternate link relation to indicate the member
type.
</documentation>
</link>
</links>
<methods>
<method name="GET">
<response>
<representation media-type-ref="med-atom" entity="atom:feed"/>
</response>
</method>
<method name="POST">
<request>
<documentation>Creates a document</documentation>
<representation media-type-ref="med-document" entity="document"/>
</request>
<response>
<documentation>Returns the newly created document</documentation>
<representation media-type-ref="med-document" entity="document"/>
</response>
</method>
</methods>
</resource>
This resource is an Atom feed that supports paging and adding new documents. The
following link relations refer to the IANA standard link relations used for paging:
<link-relation id="rel-first" name="first"/>
<link-relation id="rel-last" name="last"/>
<link-relation id="rel-next" name="next"/>
<link-relation id="rel-previous" name="previous"/>
Because this resource supports AtomPub, it has a POST method. Both the request and
the
response refer to the document
entity, as defined by the media type with the
identifier med-document
.
<method name="POST">
<request>
<documentation>Creates a document</documentation>
<representation media-type-ref="med-document" entity="document"/>
</request>
<response>
<documentation>Returns the newly created document</documentation>
<representation media-type-ref="med-document" entity="document"/>
</response>
</method>
This resource uses the IANA standard alternate
link relation to describe
the type of the collection's members:
<link link-relation-ref="rel-alternate" resource-ref="res-document">
<documentation>
In an ATOM feed, we use the alternate link relation to indicate the member type.
</documentation>
</link>
Here is the resource that corresponds to the member type:
<resource id="res-document" name="document">
<location template="/document/{oid}">
<var name="oid">
<documentation> Identifier for the document. </documentation>
</var>
</location>
<links>
<link link-relation-ref="rel-self" resource-ref="res-document"/>
</links>
<methods>
<method name="GET">
<response>
<representation media-type-ref="med-document" entity="res-document"/>
</response>
</method>
<method name="PUT">
<request>
<representation media-type-ref="med-document" entity="res-document"/>
</request>
</method>
<method name="DELETE"/>
</methods>
</resource>
Sometimes a resource has different authentication constraints than other resources
in
the same service. In our example, the about
resource does not require
authentication, even though the service has specified authentication globally. This
is
expressed using the public=true
attribute:
<resource id="res-about" name="about" public="true">
<documentation>An HTML page describing the service.</documentation>
<location uri="/about"/>
<methods>
<method name="GET">
<response>
<representation media-type-ref="med-html" entity="html"/>
</response>
</method>
</methods>
</resource>
The opposite situation is also common - a service may need no authentication on most
resources, but require authentication for specific resources such as a payment resource,
or
perhaps one resource uses a different kind of authentication from others. Both can
be
expressed using an identity-provider-ref
attribute on the resource, specifying
the authentication to be used.
The location
element is always optional, and is not part of the client
interface. It specifies a location URI or a URI template that describes the format
of a URI
that resolves to a given resource. Here are two location elements that illustrate
both
possibilities:
<location uri="/about"/>
<location template="/document/{oid}">
<var name="oid">
<documentation> Identifier for the document. </documentation>
</var>
</location>
A variable in a URI template sometimes corresponds to a URI parameter that should
be
provided by the client. This can be expressed by adding a uri-parameter-ref
attribute to the variable:
<location template="/document/{oid}">
<var name="oid" uri-parameter-ref="par-oid"/>
</location>
URI parameters can also be specified in a request. For instance, if we want to allow
an
Atom feed to be sorted, we could provide a URI parameter to specify the sort in the
GET
request:
<method name="GET">
<request>
<uri-parameters>
<uri-parameter ref="par-sortby"/>
</uri-parameters>
</request>
<response>
<representation media-type-ref="med-atom" entity="feed"/>
</response>
</method>
On a resource
element, the extends
attribute allows one
resource to inherit all items from an existing resource and extend it by adding further
items or override existing items. For instance, the following description creates
an
invoice
resource that inherits everything found in a document
resource, and adds a link to represent the customer for an invoice:
<resource id="res-invoice" name="invoice" extends="res-document">
<links>
<link link-relation-ref="rel-customer" resource-ref="res-customer"/>
</links>
</resource>
Status attributes on a resource
element can be used to track both the
design status and the implementation status:
<resource id="res-document" name="document" design-status="approved" implementation-status="poc">
property
elements can be used to specify properties of a resource. This is
typically done when more than one media type represents the same resource, in order
to
minimize redundant specification. In this case, the media types should describe how
a
property is mapped to its representation. Note that property elements are defined
purely by
documentation, they do not have a standard type system or a standard set of
datatypes.
<properties>
<property name="expiration">
<documentation>A date, representing the expiration date of the document.</documentation>
</property>
</properties>
Link Relations
Link relations are declared globally. We recommend that even IANA standard link
relations be documented for a service, because there are many standard link relations,
and
their meaning is not completely specified, their meaning needs to be specified concretely
for a given service. Link relations are declared globally and referred to from individual
resources. If the name of a link relation is not registered with IANA, its name should
be a
URI, such as identifiers.example.com/linkrel/documents
.
<link-relations>
<documentation> Link relations used in the media-type. IANA link relations can be found <ref
uri="http://www.iana.org/assignments/link-relations/link-relations.xml">here</ref>. Non-IANA
link relations will be registered on identifiers.example.com. </documentation>
<link-relation id="rel-about" name="about"/>
<link-relation id="rel-alternate" name="alternate"/>
<link-relation id="rel-self" name="self"/>
<link-relation id="rel-edit" name="edit"/>
<link-relation id="rel-first" name="first"/>
<link-relation id="rel-last" name="last"/>
<link-relation id="rel-next" name="next"/>
<link-relation id="rel-previous" name="previous"/>
<link-relation id="rel-parent" name="parent"/>
<link-relation id="rel-documents" name="identifiers.example.com/linkrel/documents"/>
</link-relations>
Headers
Headers are declared globally. We recommend that even standard HTTP headers be
documented for a service, so that clients know what is required.
<headers>
<header id="hea-authenticate" name="WWW-Authenticate" type="request"/>
</headers>
Authentication
Authentication mechanisms and identity providers are declared globally. Here is the
schema fragment for authentication:
authentication = element authentication { mechanism*, identity-provider* }
mechanism = element mechanism { id?, name, authentication-type, documentation?, scheme* }
mechanism-ref = attribute mechanism-ref { xsd:IDREF }
identity-provider = element identity-provider { id, mechanism-ref }
authentication-type = attribute authentication-type { text }
scheme = element scheme { id?, name, documentation?, scheme-parameter* }
scheme-parameter = element parameter { id?, name, documentation? }
Here is the authentication used in our example:
<authentication>
<mechanism id="aut-http" name="HTTP Authentication" authentication-type="rfc2617">
<documentation>
We use HTTP Authentication as defined in <ref uri="http://tools.ietf.org/html/rfc2617">RFC 2617</ref>
with custom schemes. If an unauthenticated user tries to access a protected resource, a
<ref status-code="sta-unauthorized"/> status is returned, along with one or more
<ref header="hea-authenticate"/> headers, each of which contains an authentication
<html:em>challenge</html:em>. The challenges consist of a scheme followed by one or more parameters.
</documentation>
<scheme name="basic">
<parameter name="realm"/>
</scheme>
<identity-provider id="idp" mechanism-ref="aut-http"/>
</mechanism>
</authentication>
Status Codes
Status codes are declared globally. In order to avoid tight coupling, we do not provide
a direct mechanism for documenting status codes for an individual request (the documentation
for a request can refer to globally declared status codes as necessary). We recommend
that a
service document any uncommon status codes or uncommon uses of status codes at the
service
level so that clients can be prepared to handle them. Details of error conditions
can be
reported with Problem Details for HTTP APIs conventions using the
http-problem
element, as specified in the schema
status-codes = element status-codes { documentation?, status-code* }
status-code = element status { code, id, documentation?, http-problem? }
status-code-ref = attribute ref { xsd:IDREF }
code = attribute code { HTTP-status-enum }
HTTP-status-enum =
"100"
| "101"
| "102"
| "200"
| "201"
| "203"
| "204"
| "205"
| "206"
| "207"
| "208"
| "301"
| "302"
| "303"
| "304"
| "305"
| "306"
| "307"
| "308"
| "400"
| "401"
| "402"
| "403"
| "404"
| "405"
| "406"
| "407"
| "408"
| "409"
| "410"
| "411"
| "412"
| "413"
| "414"
| "415"
| "416"
| "417"
| "418"
| "420"
| "422"
| "423"
| "424"
| "425"
| "426"
| "428"
| "429"
| "431"
| "444"
| "449"
| "450"
| "451"
| "494"
| "495"
| "496"
| "497"
| "499"
| "500"
| "501"
| "502"
| "503"
| "504"
| "505"
| "506"
| "507"
| "508"
| "509"
| "510"
| "511"
| "598"
| "599"
URI Parameters
URI parameters are declared globally, and can be referenced from request
s
in method
s.
<uri-parameters>
<uri-parameter id="par-sortby" name="sortby" datatype="string">
<documentation>
Specifies a sort order for the collection.
</documentation>
</uri-parameter>
</uri-parameters>
Documentation Modules
The content allowed within a documentation
element is defined by a separate
module that is imported.
include "documentation.rnc"
We have defined modules for HTML and for DocBook. A documentation
element can
have a title, which is treated much like a section header, and an inline
attribute. Documentation that contains code examples, tables, multiple sections, or
large
amounts of text can be marked inline="false"
so that a stylesheet can convert
it to endnotes, a popup window, or whatever representation is appropriate to the format
the
stylesheet produces.
Here is the first part of the HTML documentation module:
namespace html = "http://www.w3.org/1999/xhtml/"
namespace docbook = "http://docbook.org/ns/docbook"
documentation = element documentation { inline?, doc-title?, html }
inline = attribute inline { ( "true" | "false" ) }
doc-title = element title { text }
html = html-content*
html-content = (html-element | text | ref)
html-element = element html:* { html-attribute*, html-content* }
html-attribute = attribute * { text? }
Documentation frequently needs to refer to items from the RSDL description itself,
so we
support typed references interspersed with documentation:
ref = element ref {
( attribute idref { xsd:IDREF }
| attribute uri { xsd:anyURI }
| attribute media-type { xsd:IDREF }
| attribute header { xsd:IDREF }
| attribute mechanism { xsd:IDREF }
| attribute identity-provider { xsd:IDREF }
| attribute scheme { xsd:IDREF }
| attribute scheme-parameter { xsd:IDREF }
| attribute status-code { xsd:IDREF }
| attribute uri-parameter { xsd:IDREF }
| attribute resources { xsd:IDREF }
| attribute resource { xsd:IDREF }
| attribute var { xsd:IDREF }
| attribute property { xsd:IDREF }
| attribute header { xsd:IDREF }
| attribute method { xsd:IDREF }
),
text? # Uses the name of the referred item if not provided
}
We have already seen an example that uses ref
elements in the
documentation
element for a mechanism
:
<authentication>
<mechanism id="aut-http" name="HTTP Authentication" authentication-type="rfc2617">
<documentation>
We use HTTP Authentication as defined in <ref uri="http://tools.ietf.org/html/rfc2617">RFC 2617</ref>
with custom schemes. If an unauthenticated user tries to access a protected resource, a
<ref status-code="sta-unauthorized"/> status is returned, along with one or more
<ref header="hea-authenticate"/> headers, each of which contains an authentication
<html:em>challenge</html:em>. The challenges consist of a scheme followed by one or more parameters.
</documentation>
<scheme name="basic">
<parameter name="realm"/>
</scheme>
<identity-provider id="idp" mechanism-ref="aut-http"/>
</mechanism>
</authentication>
Initial Experience
RSDL is quite new. We have recently started using it for some REST projects in the
Information Intelligence Group at EMC Corporation. In this section, we would like
to share our
experiences so far.
We have found RSDL a valuable teaching tool in the hands of a teacher who is comfortable
editing XML. On two projects, one of the authors was involved with an early design
that was
having difficulty ramping up the design, and responded by editing a RSDL description
on a
shared screen during a phone call with an engineer from the project. In each case,
it was easy
to copy similar designs from existing RSDL descriptions and modify them, then provide
the RSDL
description to the engineer as an initial skeleton for the design. With a standard
description
language, we believe we will be able to grow a library of common REST design patterns
that can
be copied and modified to design a REST interface.
Before RSDL, we maintained our REST specifications largely in Wikis, and a single
design
was frequently distributed across many Wiki pages. As a specification matured, it
was
difficult to keep these pages in sync, with accurate cross-references. More than one
page
might purport to represent the same design, different pages might represent the same
information in more than one way, and the Wiki pages did little to enforce REST conventions.
RSDL makes it much easier to version a design. By checking a RSDL description into
source code
control, reviewers can see changes in the design specification along with code changes,
and it
is always possible to retrieve the design specification that corresponds to a particular
version of the code.
Before RSDL, user documentation was created from information in these Wikis, initially
by
converting it to DocBook. RSDL allows this to be done using an XSLT transformation.
We expect
to integrate RSDL into our documentation tool chain.
While the structure of a URI should not be provided to clients, we have found that
it is
important for actually implementing a service. For instance, if the URI structure
is included,
skeleton code could be generated to create stubs that can be used to implement a server,
using
a REST framework such as JAX-RS for Java.
We have been experimenting with REST clients that perform QA testing using a RSDL
description. One of us wrote a REST client that takes a RSDL file as input and issues
HTTP
requests, navigating the service, and ensuring that each response corresponds to the
RSDL
description and reporting any deviations. In effect, the test client infers the design
from
the actual implementation, and compares it to the design specified by the RSDL description.
As
a result, we found missing resources and links in the implementation, and resources
that had
been implemented but not specified, and methods that should not be available on a
resource. We
also found code that did not properly handle edge cases for data provided via URI
templates
(in the future, we may develop a fuzzer to test for this kind of problem). We have
used this
test client in our build process. When a new resource is implemented, or an existing
one is
changed, we can test to see if the RSDL was also updated appropriately. If not, the
build
fails. Because both the build process and the documentation are synchronized with
the
specification, we can guarantee that the specification, the code, and the documentation
are
kept in sync.
Future Work
This section describes some tools that have not yet been written, or in very early
stages,
that we are considering implementing.
RSDL Lint is an XSLT transform that checks a RSDL description for internal consistency.
In
its current form, it ensures that an IDREF
refers to an element of the
appropriate type, ensures that identifiers follow our in-house standards, screens
for media
types that we do not allow in our interfaces, and warns of items that cannot be reached
from
the home resource by navigation. It can be integrated into the build process, raising
either
errors or warnings. We expect to expand the functionality of RSDL Lint significantly.
When documenting REST APIs, we often want to capture the results of concrete scenarios
running on a server and show the entire sequence of calls, including the URIs, requests,
and
responses. We are writing a tool executes a message flow using an XML vocabulary that
refers
to the components of a RSDL description. This tool generates HTML to document the
requests and
responses of the message flow. As the specification evolves, or the data in the server
changes, the message flow can be run again to create up-to-date documentation.
We plan to experiment with domain-specific editors and browsers for RSDL, including
the
ability to select templates that implement standard RESTful design patterns so that
they can
be modified.
Conclusions
RSDL provides a formal notation that can be used to think more clearly about the model
for
a RESTful service. It is an XML vocabulary designed for loosely-coupled, hypermedia-driven
RESTful design, and supports the rich structure and cross references of a REST service.
We
find it useful as a teaching tool, a design tool, and a way to represent known design
patterns
that can be copied and modified in a new RESTful service. RSDL can be used to generate
documentation in various formats.
As a machine-readable description, RSDL can be used for software-based testing of
design
consistency constraints, dynamic testing of the implementation based on the design,
and in a
variety of other tools. These tools can be integrated with the build process, identifying
mismatches between the specification and the implementation. By versioning a RSDL
description
together with source code, reviewers can see changes in the design specification along
with
code changes, and it is always possible to retrieve the design specification that
corresponds
to a particular version of the code.
Appendix A. RSDL Schema
The following schema, in RELAX-NG compact syntax, defines RSDL.
default namespace rsdl = "http://identifiers.emc.com/rsdl"
include "documentation.rnc"
start = service
service =
element service {
id?,
name,
identity-provider-ref?,
documentation?,
service-start,
media-types,
resources,
link-relations?,
headers?,
authentication?,
status-codes?,
uri-parameters?
}
id = attribute id { xsd:ID }
idref = attribute ref { xsd:IDREF }
service-start = element start { idref }
identity-provider-ref = attribute identity-provider-ref { xsd:IDREF }
media-types = element media-types { documentation?, media-type* }
media-type = element media-type { id?, name, documentation?, description* }
media-type-ref = attribute media-type-ref { xsd:IDREF }
description = element description { type, href, documentation? }
type = attribute type { "rnc" | "rng" | "xsd" | "JSONSchema" | "sedola" | "text" | "html" }
href = attribute href { xsd:anyURI }
resources = element resources { id?, documentation?, resource* }
resource =
element resource {
documentation?,
id,
name,
identity-provider-ref?,
public?,
status?,
extends?,
location?,
properties?,
links?,
methods
}
name = attribute name { text }
public = attribute public { "true" }
status = implementation-status?, design-status?
implementation-status =
attribute implementation-status {
"future" | "assigned" | "poc" | "partial" | "complete" | "passed"
}
design-status =
attribute design-status { "future" | "assigned" | "poc" | "partial" | "complete" | "approved" }
# A resource can extend an existing resource definition, inheriting what it already defines.
extends = attribute extends { xsd:IDREF }
location =
element location {
documentation?,
(uri | (uri-template, var*))
}
uri-template = attribute template { xsd:string }
# URI refers to a link relation. If absent, it is a local link relation, identified by name.
# uri-parameter-ref indicates that the value is supplied by the client, using a URI parameter.
# If no uri-parameter-ref is present, the value is supplied by the server.
var = element var { documentation?, id?, name, uri?, uri-parameter-ref? }
properties = element properties { documentation?, property* }
property = element property { id?, name, documentation? }
links = element links { documentation?, link* }
link = element link { link-relation-ref, resource-ref, status?, documentation? }
resource-ref = attribute resource-ref { xsd:IDREF }
link-relation-ref = attribute link-relation-ref { xsd:anyURI }
methods = element methods { method* }
method = element method { id?, method-name, status?, request?, response? }
method-name = attribute name { http-method }
request = element request { documentation?, request-uri-parameters?, header-refs?, representation* }
response =
element response { documentation?, response-status-codes?, header-refs?, representation* }
request-uri-parameters = element uri-parameters { request-uri-parameter }
request-uri-parameter = element uri-parameter { idref }
response-status-codes =
element status-codes {
element status-code { ref }*
}
header-refs = element header-refs { documentation?, header-ref* }
header-ref = element header-ref { ref }
representation = element representation { documentation?, media-type-ref, entity? }
entity = attribute entity { text }
http-method = "GET" | "PUT" | "HEAD" | "POST" | "DELETE" | "TRACE" | "OPTIONS" | "CONNECT" | "PATCH"
link-relations = element link-relations { documentation?, link-relation* }
link-relation = element link-relation { documentation?, id, status, link-relation-name, href? }
link-relation-name = attribute name { xsd:anyURI }
headers = element headers { header* }
header = element header { id?, name, header-type, documentation? }
header-type = attribute type { "request" | "response" | "general" | "entity" }
authentication = element authentication { mechanism*, identity-provider? }
mechanism = element mechanism { id?, name, authentication-type, documentation?, scheme* }
mechanism-ref = attribute mechanism-ref { xsd:IDREF }
identity-provider = element identity-provider { id, mechanism-ref }
authentication-type = attribute authentication-type { text }
scheme = element scheme { id?, name, documentation?, scheme-parameter* }
scheme-parameter = element parameter { id?, name, documentation? }
status-codes = element status-codes { documentation?, status-code* }
status-code = element status { code, id, documentation?, http-problem? }
status-code-ref = attribute ref { xsd:IDREF }
code = attribute code { HTTP-status-enum }
HTTP-status-enum =
"100"
| "101"
| "102"
| "200"
| "201"
| "203"
| "204"
| "205"
| "206"
| "207"
| "208"
| "301"
| "302"
| "303"
| "304"
| "305"
| "306"
| "307"
| "308"
| "400"
| "401"
| "402"
| "403"
| "404"
| "405"
| "406"
| "407"
| "408"
| "409"
| "410"
| "411"
| "412"
| "413"
| "414"
| "415"
| "416"
| "417"
| "418"
| "420"
| "422"
| "423"
| "424"
| "425"
| "426"
| "428"
| "429"
| "431"
| "444"
| "449"
| "450"
| "451"
| "494"
| "495"
| "496"
| "497"
| "499"
| "500"
| "501"
| "502"
| "503"
| "504"
| "505"
| "506"
| "507"
| "508"
| "509"
| "510"
| "511"
| "598"
| "599"
http-problem = element problem { problemType, title, detail, supportId, more }
problemType = element problemType { xsd:anyURI }
title = element title { text }
detail = element detail { text }
supportId = element supportId { xsd:anyURI }
more = element more { foreign-element* }
foreign-element = element * - rsdl:* { any-attribute*, (foreign-element* | text)* }
any-attribute = attribute * { text? }
uri-parameters = element uri-parameters { documentation?, uri-parameter* }
uri-parameter =
element uri-parameter { id?, name, documentation, datatype, value-range?, default-value? }
uri-parameter-ref = attribute uri-parameter-ref { xsd:IDREF }
datatype =
attribute datatype {
"string"
| "boolean"
| "decimal"
| "float"
| "double"
| "duration"
| "dateTime"
| "time"
| "date"
| "hexBinary"
| "base64Binary"
| "anyURI"
| "integer"
| "language"
| "ID"
| "IDREF"
| "integer"
| "long"
| "short"
| "byte"
}
value-range = element value-range { text }
default-value = element default { text }
uri = attribute uri { xsd:anyURI }
# ref elements are used in the documentation modules
ref =
element ref {
((attribute idref { xsd:IDREF }
| attribute uri { xsd:anyURI }
| attribute media-type { xsd:IDREF }
| attribute header { xsd:IDREF }
| attribute mechanism { xsd:IDREF }
| attribute identity-provider { xsd:IDREF }
| attribute scheme { xsd:IDREF }
| attribute scheme-parameter { xsd:IDREF }
| attribute status-code { xsd:IDREF }
| attribute uri-parameter { xsd:IDREF }
| attribute resources { xsd:IDREF }
| attribute resource { xsd:IDREF }
| attribute var { xsd:IDREF }
| attribute property { xsd:IDREF }
| attribute header { xsd:IDREF }
| attribute method { xsd:IDREF }),
text?)
# Uses the name of the referred item if not provided
}
Appendix B. HTML module for RSDL Documentation
namespace html = "http://www.w3.org/1999/xhtml/"
documentation = element documentation { inline?, doc-title?, html }
inline = attribute inline { ( "true" | "false" ) }
doc-title = element title { text }
html = html-content*
html-content = (html-element | text | ref)
html-element = element html:* { html-attribute*, html-content* }
html-attribute = attribute * { text? }
Appendix C. DocBook module for RSDL Documentation
namespace docbook = "http://docbook.org/ns/docbook"
documentation = element documentation { inline?, doc-title?, docbook }
inline = attribute inline { ( "true" | "false" ) }
doc-title = element title { text }
docbook = docbook-content*
docbook-content = (docbook-element | text | ref)
docbook-element = element docbook:* { docbook-attribute*, docbook-content* }
docbook-attribute = attribute * { text? }
Appendix D. An XSLT Stylesheet for RSDL
The following stylesheet converts a RSDL description to an HTML page.
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:html="http://www.w3.org/1999/xhtml/"
xmlns:rsdl="http://identifiers.emc.com/rsdl">
<xsl:output method="html" encoding ="utf-8" indent="no"/>
<xsl:strip-space elements="*"/>
<xsl:key name="status" match="//rsdl:status-codes/rsdl:status" use="@code" />
<xsl:template match="/rsdl:service">
<html>
<head>
<title><xsl:call-template name="title"/></title>
<xsl:call-template name="style"/>
</head>
<body>
<div class="outline index">
<xsl:call-template name="index"/>
</div>
<div class="outline reference">
<xsl:call-template name="reference"/>
</div>
</body>
</html>
</xsl:template>
<xsl:template name="title">
<xsl:value-of select="@name"/> REST Service
</xsl:template>
<xsl:template name="style">
<style type="text/css">
body { margin: 0; padding: 0 0 0 16em; }
h1, h2 { color: Navy; }
h3 { color: Blue; }
table { border-collapse: collapse; margin-bottom: 1em; }
th, td { border: 1px solid; padding: 0.35em; vertical-align: top; }
th { color: White; background-color: CornflowerBlue; text-align: left; border-color: Black; }
td { border-color: DarkBlue; }
.outline { vertical-align: top; padding: 1em; }
.index { position: fixed; top: 0; left: 0; width: 16em; height: 96%; overflow: auto; font-size: smaller; }
.reference { height: 100%; overflow: auto; }
div { overflow: scroll; }
.homeResource {
font-weight: bold;
font-size: smaller;
background-color: Green;
color: Yellow;
padding: 0.3em;
margin-left: 1em;
border-radius: 1em;
}
#hint {
display: none;
font-size: small;
font-weight: normal;
white-space: nowrap;
background-color: LightYellow;
color: DimGrey;
border: 1px solid DimGrey;
border-radius: 0.5em;
padding: 0.5em;
margin-right: 0.5em;
}
#full { color: Green; margin-right: 0.2em; }
#full:hover ~ #hint { display: inline; }
#no { color: Red; margin-right: 0.2em; }
#no:hover ~ #hint { display: inline; }
#partial { color: Coral; margin-right: 0.3em; }
#partial:hover ~ #hint { display: inline; }
.one-piece { white-space: nowrap; text-wrap: none; }
.center { text-align: center; }
.button {
background-color: LightGrey;
color: Black;
font-size: smaller;
border: 1px solid DarkGrey;
border-radius: 0.35em;
padding: 0.35em;
text-decoration: none;
}
.header-suffix { font-size: small; }
</style>
</xsl:template>
<xsl:template name="index">
<xsl:call-template name="index-resources"/>
<xsl:call-template name="index-media-types"/>
<xsl:call-template name="index-link-relations"/>
<xsl:call-template name="index-uri-parameters"/>
<xsl:call-template name="index-custom-headers"/>
<xsl:call-template name="index-status-codes"/>
<xsl:call-template name="index-authentication-mechanisms"/>
</xsl:template>
<xsl:template name="index-resources">
<h3>Resources</h3>
<xsl:for-each select="//rsdl:resources/rsdl:resource">
<xsl:sort select="@name"/>
<a class="item">
<xsl:attribute name="style">
top: <xsl:value-of select="4 + position()"/>em;
</xsl:attribute>
<xsl:attribute name="href">#<xsl:value-of select="@id"/></xsl:attribute>
<code><xsl:value-of select="@name"/></code>
</a>
<xsl:call-template name="home-resource"/>
<br/>
</xsl:for-each>
</xsl:template>
<xsl:template name="home-resource">
<xsl:if test="@id = /rsdl:service/@home-resource">
<span class="homeResource">Home resource</span>
</xsl:if>
</xsl:template>
<xsl:template name="index-media-types">
<h3>Media Types</h3>
<xsl:for-each select="//rsdl:media-types/rsdl:media-type">
<xsl:sort select="@name"/>
<a class="item">
<xsl:attribute name="style">
top: <xsl:value-of select="4 + position()"/>em;
</xsl:attribute>
<xsl:attribute name="href">#<xsl:value-of select="@id"/></xsl:attribute>
<code><xsl:value-of select="@name"/></code>
</a>
<br/>
</xsl:for-each>
</xsl:template>
<xsl:template name="index-link-relations">
<h3>Link Relations</h3>
<xsl:for-each select="//rsdl:link-relations/rsdl:link-relation">
<xsl:sort select="@name"/>
<a class="item">
<xsl:attribute name="style">
top: <xsl:value-of select="4 + position()"/>em;
</xsl:attribute>
<xsl:attribute name="href">#<xsl:value-of select="@id"/></xsl:attribute>
<code><xsl:value-of select="@name"/></code>
</a>
<br/>
</xsl:for-each>
</xsl:template>
<xsl:template name="index-authentication-mechanisms">
<xsl:if test="//rsdl:authentication/rsdl:uri-mechanism">
<h3>Authentication Mechanisms</h3>
<xsl:for-each select="//rsdl:authentication/rsdl:mechanism">
<xsl:sort select="@name"/>
<a class="item">
<xsl:attribute name="style">
top: <xsl:value-of select="4 + position()"/>em;
</xsl:attribute>
<xsl:attribute name="href">#<xsl:value-of select="@id"/></xsl:attribute>
<code><xsl:value-of select="@name"/></code>
</a>
<br/>
</xsl:for-each>
</xsl:if>
</xsl:template>
<xsl:template name="index-status-codes">
<xsl:if test="//rsdl:status-codes/rsdl:status">
<h3>Status Codes</h3>
<xsl:for-each select="//rsdl:status-codes/rsdl:status">
<xsl:sort select="@code"/>
<a class="item">
<xsl:attribute name="style">
top: <xsl:value-of select="4 + position()"/>em;
</xsl:attribute>
<xsl:attribute name="href">#<xsl:value-of select="@id"/></xsl:attribute>
<code><xsl:value-of select="@code"/></code>
</a>
<br/>
</xsl:for-each>
</xsl:if>
</xsl:template>
<xsl:template name="index-custom-headers">
<xsl:if test="//rsdl:custom-headers/rsdl:custom-header">
<h3>Headers</h3>
<xsl:for-each select="//rsdl:custom-headers/rsdl:custom-header">
<xsl:sort select="@name"/>
<a class="item">
<xsl:attribute name="style">
top: <xsl:value-of select="4 + position()"/>em;
</xsl:attribute>
<xsl:attribute name="href">#<xsl:value-of select="@id"/></xsl:attribute>
<code><xsl:value-of select="@name"/></code>
</a>
<br/>
</xsl:for-each>
</xsl:if>
</xsl:template>
<xsl:template name="index-uri-parameters">
<xsl:if test="//rsdl:uri-parameters/rsdl:uri-parameter">
<h3>URI Parameters</h3>
<xsl:for-each select="//rsdl:uri-parameters/rsdl:uri-parameter">
<xsl:sort select="@name"/>
<a class="item">
<xsl:attribute name="style">
top: <xsl:value-of select="4 + position()"/>em;
</xsl:attribute>
<xsl:attribute name="href">#<xsl:value-of select="@id"/></xsl:attribute>
<code><xsl:value-of select="@name"/></code>
</a>
<br/>
</xsl:for-each>
</xsl:if>
</xsl:template>
<xsl:template name="reference">
<h1><xsl:call-template name="title"/></h1>
<xsl:call-template name="resources"/>
<xsl:call-template name="media-types"/>
<xsl:call-template name="link-relations"/>
<xsl:call-template name="uri-parameters"/>
<xsl:call-template name="custom-headers"/>
<xsl:call-template name="status-codes"/>
<xsl:call-template name="authentication-mechanisms"/>
</xsl:template>
<xsl:template name="resources">
<h2>Resources</h2>
<xsl:for-each select="//rsdl:resource">
<xsl:sort select="@name"/>
<hr/>
<h3>
<a>
<xsl:attribute name="name"><xsl:value-of select="@id"/></xsl:attribute>
</a>
<xsl:call-template name="implemented"/>
<code><xsl:value-of select="@name"/></code>
<xsl:call-template name="home-resource"/>
</h3>
<xsl:apply-templates select="rsdl:documentation"/>
<xsl:call-template name="authentication"/>
<xsl:apply-templates select="*[local-name() != 'methods' and local-name() != 'documentation']"/>
<xsl:call-template name="methods"/>
</xsl:for-each>
</xsl:template>
<xsl:template name="authentication">
<xsl:choose>
<xsl:when test="/service/@identity-provider-ref and @public = 'true'">
<xsl:call-template name="no-authentication"/>
</xsl:when>
<xsl:when test="@identity-provider-ref">
<xsl:call-template name="identity-provider">
<xsl:with-param name="id" select="@identity-provider-ref"/>
</xsl:call-template>
</xsl:when>
<xsl:when test="/service/@identity-provider-ref">
<xsl:variable name="id" select="/service/@identity-provider-ref"/>
<h4>Authentication</h4>
<p>
<xsl:apply-templates select="//authentication/identity-provider[@id = $id]"/>
</p>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="no-authentication"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="no-authentication">
<xsl:if test="//rsdl:authentication/rsdl:mechanism">
<h4>Authentication</h4>
<p>This resource requires no authentication.</p>
</xsl:if>
</xsl:template>
<xsl:template name="identity-provider">
<xsl:param name="id"/>
<xsl:variable name="idp" select="//rsdl:authentication/rsdl:identity-provider[@id = $id]"/>
<xsl:variable name="mechanismId" select="$idp/@mechanism-ref"/>
<xsl:variable name="mechanism" select="//rsdl:authentication/rsdl:mechanism[@id = $mechanismId]"/>
<h4>Authentication</h4>
<table>
<tr>
<th>Mechanism</th>
<th>Identity Provider</th>
</tr>
<tr>
<td>
<a>
<xsl:attribute name="href">#<xsl:value-of select="$mechanismId"/></xsl:attribute>
<xsl:apply-templates select="$mechanism/@name"/>
</a>
</td>
<td>
<xsl:apply-templates select="$idp/rsdl:documentation"/>
</td>
</tr>
</table>
</xsl:template>
<xsl:template name="implemented">
<xsl:choose>
<xsl:when test="@status = 'full'">
<span id="full">✔</span><span id="hint">Fully implemented</span>
</xsl:when>
<xsl:when test="@status = 'partial'">
<span id="partial">?</span><span id="hint">Partially implemented</span>
</xsl:when>
<xsl:otherwise>
<span id="no">✘</span><span id="hint">Not implemented</span>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="rsdl:documentation">
<xsl:apply-templates select="text()|*"/>
</xsl:template>
<xsl:template match="rsdl:authentication">
<xsl:variable name="mechanism" select="@mechanism-ref"/>
<h4>Authentication</h4>
<p>
<a>
<xsl:attribute name="href">#<xsl:value-of select="$mechanism"/></xsl:attribute>
<xsl:value-of select="//rsdl:authentication/rsdl:mechanism[@id = $mechanism]/@name"/>
</a>.  <xsl:apply-templates select="*"/>
</p>
</xsl:template>
<xsl:template match="*">
<xsl:element name="{local-name()}">
<xsl:apply-templates select="*|@*|text()"/>
</xsl:element>
</xsl:template>
<xsl:template match="text()">
<xsl:value-of select="."/>
</xsl:template>
<xsl:template match="rsdl:ref">
<xsl:choose>
<xsl:when test="@resource and ancestor::rsdl:resource/@id = @resource">
<code>
<xsl:value-of select="@resource"/>
</code>
</xsl:when>
<xsl:otherwise>
<xsl:choose>
<xsl:when test="@resource">
<xsl:variable name="id" select="@resource"/>
<xsl:call-template name="ref-by-id">
<xsl:with-param name="id" select="$id"/>
<xsl:with-param name="name" select="//rsdl:resources/rsdl:resource[@id = $id]/@name"/>
</xsl:call-template>
</xsl:when>
<xsl:when test="@status-code">
<xsl:variable name="id" select="@status-code"/>
<xsl:call-template name="ref-by-id">
<xsl:with-param name="id" select="$id"/>
<xsl:with-param name="name" select="//rsdl:status-codes/rsdl:status[@id = $id]/@code"/>
</xsl:call-template>
</xsl:when>
<xsl:when test="@uri-parameter">
<xsl:variable name="id" select="@uri-parameter"/>
<xsl:call-template name="ref-by-id">
<xsl:with-param name="id" select="$id"/>
<xsl:with-param name="name" select="//rsdl:uri-parameters/rsdl:uri-parameter[@id = $id]/@name"/>
</xsl:call-template>
</xsl:when>
<xsl:when test="@custom-header">
<xsl:variable name="id" select="@custom-header"/>
<xsl:call-template name="ref-by-id">
<xsl:with-param name="id" select="$id"/>
<xsl:with-param name="name" select="//rsdl:custom-headers/rsdl:custom-header[@id = $id]/@name"/>
</xsl:call-template>
</xsl:when>
<xsl:when test="@mechanism">
<xsl:variable name="id" select="@mechanism"/>
<xsl:call-template name="ref-by-id">
<xsl:with-param name="id" select="$id"/>
<xsl:with-param name="name" select="//rsdl:authentication/rsdl:mechanism[@id = $id]/@name"/>
</xsl:call-template>
</xsl:when>
<xsl:when test="@media-type">
<xsl:variable name="id" select="@media-type"/>
<xsl:call-template name="ref-by-id">
<xsl:with-param name="id" select="$id"/>
<xsl:with-param name="name" select="//rsdl:media-types/rsdl:media-type[@id = $id]/@name"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<a>
<xsl:attribute name="href">
<xsl:value-of select="@uri"/>
</xsl:attribute>
<xsl:apply-templates select="*|text()"/>
</a>
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="ref-by-id">
<xsl:param name="id"/>
<xsl:param name="name"/>
<a>
<xsl:attribute name="href">#<xsl:value-of select="$id"/></xsl:attribute>
<xsl:choose>
<xsl:when test="text()">
<xsl:apply-templates select="*|text()"/>
</xsl:when>
<xsl:otherwise>
<code>
<xsl:value-of select="$name"/>
</code>
</xsl:otherwise>
</xsl:choose>
</a>
</xsl:template>
<xsl:template name="methods">
<xsl:if test="rsdl:methods/rsdl:method">
<xsl:variable name="showStatus" select="rsdl:methods/rsdl:method/@status"/>
<h4>Supported Methods</h4>
<table>
<tr>
<xsl:if test="$showStatus">
<th>Status</th>
</xsl:if>
<th>Name</th>
<xsl:if test="rsdl:methods/rsdl:method/rsdl:request">
<th>Request</th>
</xsl:if>
<xsl:if test="rsdl:methods/rsdl:method/rsdl:response">
<th>Response</th>
</xsl:if>
</tr>
<xsl:for-each select="rsdl:methods//rsdl:method">
<tr>
<xsl:if test="$showStatus">
<td class="center">
<xsl:call-template name="implemented"/>
</td>
</xsl:if>
<td>
<code><xsl:value-of select="@name"/></code>
</td>
<xsl:if test="../rsdl:method/rsdl:request">
<td>
<xsl:apply-templates select="rsdl:request/*"/>
</td>
</xsl:if>
<xsl:if test="../rsdl:method/rsdl:response">
<td>
<xsl:apply-templates select="rsdl:response/*"/>
</td>
</xsl:if>
</tr>
</xsl:for-each>
</table>
</xsl:if>
</xsl:template>
<xsl:template match="rsdl:status-codes">
<em>Status code<xsl:if test="count(rsdl:status-code) > 0">s</xsl:if>:</em> 
<xsl:for-each select="rsdl:status-code">
<xsl:variable name="statusId" select="@status-code-ref"/>
<a>
<xsl:attribute name="href">#<xsl:value-of select="$statusId"/></xsl:attribute>
<code><xsl:value-of select="//rsdl:status-codes/rsdl:status[@id = $statusId]/@code"/></code>
</a>
<xsl:if test="position() < count(../rsdl:status-code)">,  </xsl:if>
</xsl:for-each>
<br/>
</xsl:template>
<xsl:template match="rsdl:header">
<xsl:variable name="id" select="@header-ref"/>
<em>Header:</em> 
<a>
<xsl:attribute name="href">#<xsl:value-of select="$id"/></xsl:attribute>
<code>
<xsl:apply-templates select="//rsdl:custom-headers/rsdl:custom-header[@id = $id]/@name"/>
</code>
</a>
<br/>
</xsl:template>
<xsl:template match="rsdl:representation">
<xsl:variable name="id" select="@media-type-ref"/>
<xsl:if test="../rsdl:documentation">
<br/>
</xsl:if>
<em>Media type:</em> <code>
<a>
<xsl:attribute name="href">#<xsl:value-of select="$id"/></xsl:attribute>
<xsl:value-of select="//rsdl:media-types/rsdl:media-type[@id = $id]/@name"/>
</a>
</code>
<xsl:if test="@entity">, entity: <code><xsl:value-of select="@entity"/></code></xsl:if>
<xsl:if test="@entry">
<xsl:variable name="resId" select="@entry"/>
<xsl:text>, entry:</xsl:text> 
<code>
<a>
<xsl:attribute name="href">#<xsl:value-of select="$resId"></xsl:value-of></xsl:attribute>
<xsl:value-of select="//rsdl:resources/rsdl:resource[@id = $resId]/@name"/>
</a>
</code>
</xsl:if>
<xsl:if test="rsdl:documentation">
<br/>    <xsl:apply-templates select="rsdl:documentation"/>
</xsl:if>
<br/>
</xsl:template>
<xsl:template match="rsdl:links">
<xsl:if test="rsdl:link">
<h4>Links to other resources</h4>
<xsl:variable name="showStatus" select="rsdl:link/@status"/>
<table>
<tr>
<xsl:if test="$showStatus">
<th>Status</th>
</xsl:if>
<th>Relation</th>
<th>Resource</th>
<xsl:if test="rsdl:link/rsdl:documentation">
<th>Description</th>
</xsl:if>
</tr>
<xsl:for-each select="rsdl:link">
<xsl:sort select="@resource-ref"/>
<xsl:variable name="resId" select="@resource-ref"/>
<xsl:variable name="relId" select="@link-relation-ref"/>
<tr>
<xsl:if test="$showStatus">
<td class="center">
<xsl:call-template name="implemented"/>
</td>
</xsl:if>
<td>
<code>
<a>
<xsl:attribute name="href">#<xsl:value-of select="$relId"></xsl:value-of></xsl:attribute>
<xsl:value-of select="//rsdl:link-relations/rsdl:link-relation[@id = $relId]/@name"/>
</a>
</code>
</td>
<td>
<code>
<a>
<xsl:attribute name="href">#<xsl:value-of select="$resId"></xsl:value-of></xsl:attribute>
<xsl:value-of select="//rsdl:resources/rsdl:resource[@id = $resId]/@name"/>
</a>
</code>
</td>
<xsl:if test="../rsdl:link/rsdl:documentation">
<td>
<xsl:apply-templates select="rsdl:documentation/*|rsdl:documentation/text()"/>
</td>
</xsl:if>
</tr>
</xsl:for-each>
</table>
</xsl:if>
</xsl:template>
<xsl:template match="rsdl:location">
<xsl:choose>
<xsl:when test="../@id = /rsdl:service/@home-resource">
<h4>Location</h4>
<p>
Reach this resource at <code><xsl:value-of select="@href"/></code>.
</p>
</xsl:when>
<xsl:when test="@template and rsdl:var[@uri-parameter-ref]">
<h4>URI Parameters</h4>
<table>
<tr>
<th>Name</th>
<th>Description</th>
</tr>
<xsl:for-each select="rsdl:var">
<xsl:sort select="@name"/>
<xsl:variable name="id" select="@uri-parameter-ref"/>
<tr>
<td><code><xsl:value-of select="@name"/></code></td>
<td><xsl:apply-templates select="//rsdl:uri-parameters/rsdl:uri-parameter[@id = $id]/rsdl:documentation"/></td>
</tr>
</xsl:for-each>
</table>
</xsl:when>
</xsl:choose>
</xsl:template>
<xsl:template name="authentication-mechanisms">
<xsl:if test="//rsdl:authentication/rsdl:mechanism">
<hr/>
<h2>Authentication Mechanisms</h2>
<xsl:for-each select="//rsdl:authentication/rsdl:mechanism">
<xsl:sort select="@name"/>
<h3>
<a>
<xsl:attribute name="name"><xsl:value-of select="@id"/></xsl:attribute>
</a>
<code><xsl:value-of select="@name"/></code>
</h3>
<xsl:apply-templates select="rsdl:documentation"/>
<xsl:for-each select="rsdl:scheme">
<xsl:sort select="@name"/>
<xsl:apply-templates select="." />
</xsl:for-each>
</xsl:for-each>
</xsl:if>
</xsl:template>
<xsl:template match="rsdl:scheme">
<h4>Scheme: <em><xsl:value-of select="@name"/></em></h4>
<xsl:if test="rsdl:documentation">
<p><xsl:apply-templates select="rsdl:documentation"/></p>
</xsl:if>
<xsl:if test="rsdl:parameter">
<table>
<tr>
<th>Parameter</th>
<th>Description</th>
</tr>
<xsl:for-each select="rsdl:parameter">
<xsl:sort select="@name"/>
<tr>
<td><code><xsl:value-of select="@name"/></code></td>
<td><xsl:apply-templates select="rsdl:documentation"/></td>
</tr>
</xsl:for-each>
</table>
</xsl:if>
</xsl:template>
<xsl:template name="status-codes">
<xsl:if test="//rsdl:status-codes/rsdl:status">
<hr/>
<h2>Status Codes</h2>
<xsl:for-each select="//rsdl:status-codes/rsdl:status">
<xsl:sort select="@code"/>
<h3>
<a>
<xsl:attribute name="name"><xsl:value-of select="@id"/></xsl:attribute>
</a>
<code><xsl:value-of select="@code"/></code>
</h3>
<xsl:apply-templates/>
</xsl:for-each>
</xsl:if>
</xsl:template>
<xsl:template name="custom-headers">
<xsl:if test="//rsdl:custom-headers/rsdl:custom-header">
<hr/>
<h2>Headers</h2>
<xsl:for-each select="//rsdl:custom-headers/rsdl:custom-header">
<xsl:sort select="@name"/>
<h3>
<a>
<xsl:attribute name="name"><xsl:value-of select="@id"/></xsl:attribute>
</a>
<code><xsl:value-of select="@name"/></code>  <span class="header-suffix">(<xsl:value-of select="@type"/>)</span>
</h3>
<xsl:apply-templates/>
</xsl:for-each>
</xsl:if>
</xsl:template>
<xsl:template name="media-types">
<hr/>
<h2>Media-types</h2>
<xsl:for-each select="//rsdl:media-types/rsdl:media-type">
<xsl:sort select="@name"/>
<h3>
<a>
<xsl:attribute name="name"><xsl:value-of select="@id"/></xsl:attribute>
</a>
<code><xsl:value-of select="@name"/></code>
</h3>
<xsl:apply-templates/>
</xsl:for-each>
</xsl:template>
<xsl:template match="rsdl:description">
<br/>
<xsl:choose>
<xsl:when test="@type = 'html'">
<a>
<xsl:attribute name="href">
<xsl:value-of select="@href"/>
</xsl:attribute>
More information
</a>
</xsl:when>
<xsl:when test="@type = 'sedola'">
<a>
<xsl:attribute name="href">
<xsl:value-of select="@href"/>
</xsl:attribute>
Service registration
</a>
</xsl:when>
<xsl:when test="@type = 'xsd'">
<a>
<xsl:attribute name="href">
<xsl:value-of select="@href"/>
</xsl:attribute>
XML Schema
</a>
</xsl:when>
<xsl:when test="@type = 'rnc'">
<a>
<xsl:attribute name="href">
<xsl:value-of select="@href"/>
</xsl:attribute>
Relax NG Schema
</a>
</xsl:when>
</xsl:choose>
</xsl:template>
<xsl:template name="link-relations">
<hr/>
<h2>Link Relations</h2>
<xsl:for-each select="//rsdl:link-relations/rsdl:link-relation">
<xsl:sort select="@name"/>
<h3>
<a>
<xsl:attribute name="name"><xsl:value-of select="@id"/></xsl:attribute>
</a>
<code><xsl:value-of select="@name"/></code>
</h3>
<xsl:apply-templates/>
</xsl:for-each>
</xsl:template>
<xsl:template name="uri-parameters">
<xsl:if test="//rsdl:uri-parameters/rsdl:uri-parameter">
<hr/>
<h2>URI Parameters</h2>
<xsl:for-each select="//rsdl:uri-parameters/rsdl:uri-parameter">
<xsl:sort select="@name"/>
<h3>
<a>
<xsl:attribute name="name"><xsl:value-of select="@id"/></xsl:attribute>
</a>
<code><xsl:value-of select="@name"/></code>
</h3>
<xsl:apply-templates/>
</xsl:for-each>
</xsl:if>
</xsl:template>
<xsl:template match="rsdl:properties">
<xsl:if test="rsdl:property">
<h4>Properties</h4>
<table>
<tr>
<th>Name</th>
<th>Description</th>
</tr>
<xsl:for-each select="rsdl:property">
<xsl:sort select="@name"/>
<tr>
<td><code><xsl:value-of select="@name"/></code></td>
<td><xsl:apply-templates select="rsdl:documentation"/></td>
</tr>
</xsl:for-each>
</table>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Appendix E. RSDL Description for the Planets Service
The following example is taken from RESTful Web Services, chapter 5.
<?xml version="1.0" ?>
<service name="Maps"
xmlns:html="http://www.w3.org/1999/xhtml/" xmlns="http://identifiers.emc.com/rsdl"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://identifiers.emc.com/rsdl rsdl.xsd"
>
<documentation>
This is an example from the book RESTful Web Services, chapter 5.
</documentation>
<start ref="res-planets"/>
<media-types>
<media-type id="med-xhtml" name="application/xhtml+xml">
<documentation>
We are defining an XHTML <html:em>microformat</html:em> by adding meaning using the <html:code>class</html:code>
attribute to elements. For example, adding <html:code>class="planets"</html:code> to the
<html:code>ul</html:code> element, we can turn a list into a list of planets.
</documentation>
<description type="html" href="http://tools.ietf.org/html/rfc3236" />
</media-type>
<media-type id="med-png" name="image/png">
<description type="html" href="http://www.iana.org/assignments/media-types/image/png" />
</media-type>
</media-types>
<resources>
<resource id="res-planets" name="planets">
<location uri="/"/>
<links>
<link link-relation-ref="rel-place" resource-ref="res-place"/>
</links>
<methods>
<method name="GET">
<response>
<representation media-type-ref="med-xhtml" entity="html"/>
</response>
</method>
</methods>
</resource>
<resource id="res-place" name="place">
<location template="/{planet}/[{scoping-information}/][{place-name}]{?show}">
<var name="planet" uri-parameter-ref="par-planet"/>
<var name="scoping-information" uri-parameter-ref="par-scoping-information"/>
<var name="place-name" uri-parameter-ref="par-place-name"/>
<var name="show" uri-parameter-ref="par-show"/>
</location>
<links>
<link link-relation-ref="rel-map" resource-ref="res-map"/>
<link link-relation-ref="rel-point" resource-ref="res-point"/>
<link link-relation-ref="rel-place" resource-ref="res-place"/>
</links>
<methods>
<method name="GET">
<response>
<representation media-type-ref="med-xhtml" entity="html"/>
</response>
</method>
</methods>
</resource>
<resource id="res-point" name="point">
<location template="/{planet}/{latitude},{longitude}">
<var name="planet" uri-parameter-ref="par-planet"/>
<var name="latitude" uri-parameter-ref="par-latitude"/>
<var name="longitude" uri-parameter-ref="par-longitude"/>
</location>
<links>
<link link-relation-ref="rel-place" resource-ref="res-place"/>
<link link-relation-ref="rel-point" resource-ref="res-point"/>
</links>
<methods>
<method name="GET">
<response>
<representation media-type-ref="med-xhtml" entity="html"/>
</response>
</method>
</methods>
</resource>
<resource id="res-map" name="map">
<location template="/{map-type}{scale}/{planet}/{latitude},{longitude}">
<var name="map-type" uri-parameter-ref="par-map-type"/>
<var name="scale" uri-parameter-ref="par-scale"/>
<var name="planet" uri-parameter-ref="par-planet"/>
<var name="latitude" uri-parameter-ref="par-latitude"/>
<var name="longitude" uri-parameter-ref="par-longitude"/>
</location>
<links>
<link link-relation-ref="rel-image" resource-ref="res-image"/>
<link link-relation-ref="rel-map" resource-ref="res-map"/>
</links>
<methods>
<method name="GET">
<response>
<representation media-type-ref="med-xhtml" entity="html"/>
</response>
</method>
</methods>
</resource>
<resource id="res-image" name="image">
<location template="/{map-type}{scale}/{planet}/images/{latitude},{longitude}.png">
<var name="map-type" uri-parameter-ref="par-map-type"/>
<var name="scale" uri-parameter-ref="par-scale"/>
<var name="planet" uri-parameter-ref="par-planet"/>
<var name="latitude" uri-parameter-ref="par-latitude"/>
<var name="longitude" uri-parameter-ref="par-longitude"/>
</location>
<methods>
<method name="GET">
<response>
<representation media-type-ref="med-png"/>
</response>
</method>
</methods>
</resource>
</resources>
<link-relations>
<link-relation id="rel-place" name="place">
<documentation>
The target resource is a related place. Links of this type are found by looking for <html:code>a</html:code>
elements with <html:code>class="place"</html:code>. Additionally, you can find search links to places via
the <html:code>form</html:code> element with <html:code>id="searchPlace"</html:code>.
</documentation>
</link-relation>
<link-relation id="rel-point" name="point">
<documentation>
The target resource is a related point on a planet. Links of this type are found by looking for
<html:code>a</html:code> elements with different values for the <html:code>class</html:code> attribute,
like <html:code>coordinates</html:code>, <html:code>map_nav</html:code>, <html:code>zoom_in</html:code>,
and <html:code>zoom_out</html:code>.
</documentation>
</link-relation>
<link-relation id="rel-map" name="map">
<documentation>
The target resource is a map related to the current resource. Links of this type are found by looking for
<html:code>a</html:code>
elements with <html:code>class="map"</html:code>.
</documentation>
</link-relation>
<link-relation id="rel-image" name="image">
<documentation>
The target resource is an image related to the current resource. Links of this type are found by looking for
<html:code>img</html:code>
elements with <html:code>class="map"</html:code>.
</documentation>
</link-relation>
</link-relations>
<uri-parameters>
<uri-parameter id="par-planet" name="planet" datatype="string">
<documentation>
Human friendly name of a planet, like <html:code>Earth</html:code>.
</documentation>
</uri-parameter>
<uri-parameter id="par-place-name" name="place-name" datatype="string">
<documentation>
Human friendly name of a place, like <html:code>Mount%20Rushmore</html:code>.
</documentation>
</uri-parameter>
<uri-parameter id="par-scoping-information" name="scoping-information" datatype="string">
<documentation>
A hierarchy of <ref uri-parameter="par-place-name">place names</ref> like
<html:code>/USA/New%20England/Maine/</html:code>.
</documentation>
</uri-parameter>
<uri-parameter id="par-map-type" name="map-type" datatype="string">
<documentation>
The type of map, like <html:code>satellite</html:code>.
</documentation>
</uri-parameter>
<uri-parameter id="par-scale" name="scale" datatype="string">
<documentation>
Dot followed by an integer, like <html:code>.1</html:code>. A bigger number indicates more details.
</documentation>
</uri-parameter>
<uri-parameter id="par-show" name="show" datatype="string">
<documentation>
Things to search for near a given place, like <html:code>diners</html:code>.
</documentation>
</uri-parameter>
<uri-parameter id="par-latitude" name="latitude" datatype="float">
<documentation>
Latitude on a planet, like <html:code>24.9195</html:code>.
</documentation>
</uri-parameter>
<uri-parameter id="par-longitude" name="longitude" datatype="float">
<documentation>
Longitude on a planet, like <html:code>17.821</html:code>.
</documentation>
</uri-parameter>
</uri-parameters>
</service>
References
[WADL] Marc Hadley, Sun Microsystems. Web Application Description Language, W3C Member Submission 31 August 2009.
http://www.w3.org/Submission/wadl/.
[URI Templates] Joe Gregorio, Google; Roy Fielding,
Adobe; Marc Hadley, MITRE; Mark Nottingham, Rackspace; David Orchard, Salesforce.com.
URI Template, IETF RFC 6570, March 2012.
http://tools.ietf.org/html/rfc6570
[JSON Home Documents] Mark Nottingham, Rackspace.
Home Documents for HTTP APIs, May 8, 2013.
http://www.ietf.org/id/draft-nottingham-json-home-03.txt
[XML Home Documents] Erik Wilde, EMC. Home Documents for HTTP Services: XML Syntax, June 11, 2013.
http://www.ietf.org/id/draft-wilde-home-xml-01.txt
[Media Type Specifications and Registration Procedures] N. Freed, Oracle; J.
Klensin; T. Hansen, AT&T Laboratories. Media Type Specifications and
Registration Procedures, IETF RFC 6838, January 2013.
http://tools.ietf.org/html/rfc6838
[To WADL or not to WADL] Bill Burke. To WADL or not to WADL, blog post, May 21, 2009.
http://bill.burkecentral.com/2009/05/21/to-wadl-or-not-to-wadl/.
[REST APIs must be hypertext-driven] Roy
Fielding. REST APIs must be hypertext-driven, blog post, Mon
20 Oct 2008.
http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven/.
[Home Documents for HTTP APIs]
Home Documents for HTTP APIs.
http://tools.ietf.org/html/draft-nottingham-json-home-02
[Problem Details for HTTP APIs]
Problem Details for HTTP APIs.
http://datatracker.ietf.org/doc/draft-nottingham-http-problem/
[XML Media Types]
XML Media Types, IETF RFC 3023, MURATA Makoto (FAMILY Given),
Simon St.Laurent, Daniel Kohn. http://tools.ietf.org/html/rfc3023
[Media Type Specifications and Registration Procedures]
Media Type Specifications and Registration Procedures, IETF
RFC 4288, Ned Freed, John C. Klensin.
http://tools.ietf.org/html/rfc4288
[Additional Media Type Structured Syntax Suffixes]
Additional Media Type Structured Syntax Suffixes, IETF RFC
5830, Tony Hansen, Alexey Melnikov.
http://tools.ietf.org/html/rfc4288
[Does REST need a service description language]
Aristotle Pagaltzis. Does REST need a service description
language?, blog post, May 27, 2007.
http://plasmasturm.org/log/460/.
[How RESTful is Your API?] Cory House. How RESTful is your API?, blog post, August 26, 2012.
http://www.bitnative.com/2012/08/26/how-restful-is-your-api/.
[Richardson Maturity Model] Martin Fowler. Richardson Maturity Model: steps toward the glory of REST, blog post,
18 March 2010.
http://martinfowler.com/articles/richardsonMaturityModel.html.
[What's Wrong with WADL?] Dare Obasanjo. What's Wrong with WADL?, blog post, June 4, 2007.
http://www.25hoursaday.com/weblog/2007/06/04/WhatsWrongWithWADL.aspx
[REST in Practice] Jim Webber, Savas Parastatidis and Ian
Robinson. REST in Practice: Hypermedia and Systems
Architecture. O'Reilly Media; 1 edition (September 24, 2010). ISBN-13:
978-0596805821.
[RESTful Web Services] Leonard Richardson, Sam Ruby
RESTful Web Services. O'Reilly Media; Dec 17, 2008f.
ISBN-13: 978-0596554606.
[Sedola] Erik Wilde. Service
Documentation Language.
https://github.com/dret/sedola/
[Architectural Styles and the Design of Network-based Software Architectures, PhD Dissertation
Thesis.] Roy Thomas Fielding, Architectural Styles and the Design of
Network-based Software Architectures, PhD Dissertation Thesis, University of
California, Irvine © 2000.
http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm.
×Joe Gregorio, Google; Roy Fielding,
Adobe; Marc Hadley, MITRE; Mark Nottingham, Rackspace; David Orchard, Salesforce.com.
URI Template, IETF RFC 6570, March 2012.
http://tools.ietf.org/html/rfc6570
×N. Freed, Oracle; J.
Klensin; T. Hansen, AT&T Laboratories. Media Type Specifications and
Registration Procedures, IETF RFC 6838, January 2013.
http://tools.ietf.org/html/rfc6838
×Roy
Fielding. REST APIs must be hypertext-driven, blog post, Mon
20 Oct 2008.
http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven/.
×Jim Webber, Savas Parastatidis and Ian
Robinson. REST in Practice: Hypermedia and Systems
Architecture. O'Reilly Media; 1 edition (September 24, 2010). ISBN-13:
978-0596805821.
×Leonard Richardson, Sam Ruby
RESTful Web Services. O'Reilly Media; Dec 17, 2008f.
ISBN-13: 978-0596554606.