1/RestTL - a RESTful Transport Layer

This document defines a RESTful Transport Layer (RestTL), a way of working with server-held resources in a RESTful fashion. RestTL specifies standard rules for representing resources, and standard mechanisms for working with them in a RESTful fashion over a plain HTTP client-server network.

  • Name: www.restms.org/spec:1/RestTL
  • Version: draft/4
  • Editor: Pieter Hintjens <moc.xitami|hp#moc.xitami|hp>
  • Contributors: Steve Vinoski <gro.eeei|iksoniv#gro.eeei|iksoniv>, Brad Clements <moc.skrowkrum|ckb#moc.skrowkrum|ckb>

License

Copyright (c) 2009 by the Editor and Contributors.

This Specification is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version.

This Specification is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program; if not, see <http://www.gnu.org/licenses>.

Change Process

This document is governed by the Digital Standard Organization's Consensus-Oriented Specification System.

Goals and structure of this document

This document defines a RESTful Transport Layer (RestTL), a way of working with server-held resources in a RESTful fashion. RestTL specifies standard rules for representing resources, and standard mechanisms for working with them in a RESTful fashion over a plain HTTP client-server network.

RestTL is a foundation for arbitrary RESTful APIs including, but not limited to, RestMS. We describe:

  1. A set of HTTP requests and responses that let a client work with server-side resources in a RESTful way;
  2. A grammar for XML or JSON documents to represent server-held resources.

Language

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119[4].

These terms are introduced by, and have specific meaning, in this specification:

  • Asynclet - a resource that can be retrieved before it exists, resulting in a "long poll".

Why define a RESTful Transport Layer?

REST[1] is a design pattern rather than a formal specification. This means that architects have lattitude in how to implement more or less RESTful APIs. This is useful for experimentation but problematic for defining standards. Standards should formalize best practice in a regular way.

The principle of Least Surprise applies: the implementor, having learned the rules that apply to object A, expects them to apply to object B insofar as that makes sense. How we create and work with resources, how we name and address resources, how we represent resources: all these should as regular as possible. We do not want discussions over whether one updates a resource using PUT or POST.

The best way to enforce the regularity of such rules is to draw them out into a stand-alone specification, and document them clearly, removing redundant optionality so there is exactly one way to do anything, and no grey areas. This is such a specification.

While RestTL was designed to support RestMS, it is not restricted to that use case, and could be used to build other RESTful APIs. At the same time, RestTL does not claim to be a universal RESTful transport: it abstracts sufficient design to support RestMS, and no more.

RestTL overview

We speak of "the API" as being a RESTful protocol that we layer on top of RestTL.

RestTL is built on HTTP/HTTPS and conforms to the HTTP/1.1 specifications. It implements these HTTP methods:

  • POST - create a new resource
  • GET - retrieve a resource
  • PUT - update a resource
  • DELETE - delete a resource

It uses these HTTP headers with their HTTP/1.1 meaning:

  • Location - URI of newly created resource
  • ETag - opaque hash tag of that identifies a resource instance
  • Data-Modified - date and time that resource was modified
  • If-Modified-Since - conditional GET using resource date
  • If-None-Match - conditional GET using resource ETag
  • If-Unmodified-Since - conditional PUT or DELETE using resource date
  • If-Match - conditional PUT or DELETE using resource ETag

Additionally, it uses two custom headers to allow event-driven work:

  • When-Modified-After - GET evented on resource date change
  • When-None-Match - GET evented on resource ETag change

RestTL assumes the availability of standard HTTP client and server stacks that can handle headers such as Content-Length properly.

API resources are either public (shared by many clients) or private (to a single client). Public resources are named by formal or informal agreement, while the server is responsible for naming all private resources. The URI of a resource is based on the resource name, so clients can know the URIs of public resources in advance, while the server provides the URIs of private resources at runtime.

API resources are either structured or opaque. A structured resource has properties that both client and server can access and modify. Resources can contain references (URIs) to child resources. An opaque resource has a MIME type and a binary content that the API never examines nor modifies.

The API resource types form a static type tree attached to a root type. The set of actual resources that a server holds form a dynamic resource tree, attached to a public root resource. To navigate the resource tree, clients retrieve the root resource and inspecting it. Not all resources are discoverable: to work with a private resource an client must have created it, and thus know its URI.

The API represents structured resources as interchangeable XML or JSON resource documents, at the choice of the client. These documents follow simple grammar rules for representing resources and their properties.

Lastly the API has two mechanisms for evented asynchronous retrieval and delivery of resources, and one mechanism for event-driven monitoring of resource updates. RESTful APIs, like HTTP, are nominally synchronous and use a request-response pattern for all resource actions. The first mechanism is the asynclet resource, given a URI before it exists: the client retrieves the asynclet and receives the resource as soon as it comes into existence. The second mechanism is more typical for HTTP: streaming of new resources to the client. Lastly, using special HTTP headers a client can ask to be notified when a resource is changed.

HTTP requests and responses

Clients issue HTTP methods to work with server-side resources as follows:

  • the GET method to retrieve the representation of a known resource;
  • the POST method to create a new, dynamically named resource;
  • the PUT method to edit a known resource;
  • the DELETE method to remove a known resource.

All methods work orthogonally on all types of API resources, whether those resources contain or do not contain other resources. Not all combinations of methods and resources are meaningful, permitted, or necessarily implemented in any eventual API based on RestTL. This framework draws on the design of AtomPub[2], which may be helpful as background material.

Resource lifecycles, visibility, and addressing

API resources can be created by various parties at different times: by the server at startup, by clients at runtime, or by the server as the consequence of other events, at runtime. Only the party that created a resource can delete it, and it may place restrictions on other parties' right to work with the resource.

RestTL distinguishes between resources that are named and visible to all applications ("public resources") and resources that are unnamed and accessed via server-defined URI ("private resources").

The URI for a public resource is derived from the resource type and name as follows:

http://{server name}[:{port}]/{schema}/{resource type}/{resource name}

The fields have this meaning:

  • server name - name of host as for HTTP request
  • port - optional port as for HTTP request
  • schema - name of the API
  • resource type - name of the resource type
  • resource name - name of the resource itself

The URI for a private resource follows an identical format, where resource type is "resource" and resource name is a hash generated by the server:

http://{server-name}[:{port}]/{schema}/resource/{resource hash}

Creating a resource

Clients create new resources through the API as follows:

  • The client must know the URI of the parent for the new resource it wants to create.
  • The client POSTs a specification for the new resource to the parent URI.
  • The client creates a public resource by specifying a name. Otherwise the server names the resource.
  • The server either returns 2xx with a resource document, or 4xx or 5xx with an error text.
  • The server when it creates the resource returns "201 Created" with the new URI in the Location: header.
Client                                     Server
  |                                           |
  |  1.) POST to parent URI                   |
  |      Resource specifications              |
  |------------------------------------------>|
  |                                           |
  |  2.) 201 Created                          |
  |      Location: Resource URI               |
  |<------------------------------------------|
  |                                           |

The content body of the created resource may be different than the content body provided by the client. While the client provides specifications for the resource, the server returns the actual resulting resource, which may have additional properties and/or children.

This is the general form of a client HTTP request to create a dynamic resource, with the server response. We ignore standard HTTP headers and we assume we're using XML rather than JSON:

Client:
-------------------------------------------------
POST /{parent uri} HTTP/1.1
Content-Type: application/{schema}+xml

<?xml version="1.0"?>
<{schema} xmlns="http://www.restms.org/schema/{schema}">
  <{resource type} [name = "{name for public resource}"]>
    {resource specifications}
  </{resource type}>
</{schema}>

Server:
-------------------------------------------------
HTTP/1.1 201 Created
Content-Type: application/{schema}+xml
Date-Modified: {resource date and time}
ETag: {resource entity tag}
Location: {resource URI}

<?xml version="1.0"?>
<{schema} xmlns="http://www.restms.org/schema/{schema}">
  <{resource type} name="{resource name}"...>
    {resource contents}
  </{resource type}>
</{schema}>

The server may return these response codes specifically for a POST request:

  • 200 OK - the resource already existed as specified (only possible for public resources).
  • 201 Created - the server created the resource, and the Location: header provides the URI.
  • 400 Bad Request - the resource specification was incomplete or badly formatted.
  • 403 Forbidden - the POST method is not allowed on the parent URI.

In case of a 4xx or 5xx error response the server will return a textual error message in the content body of the response. The client should be able to handle all normal HTTP errors, such as "401 Unauthorized", "404 Not Found", "413 Too Large", "500 Internal Error", and so on.

Creating public resources is idempotent, i.e. repeated requests to create the same public resource are allowed, and safe. Clients should treat "200 OK" and "201 Created" as equally successful.

Retrieving a resource

Clients retrieve resources through the API as follows:

  • The client must know the URI of the resource that it wants to retrieve.
  • The client sends a GET method to the resource URI.
  • The client optionally specifies headers to do a conditional retrieval (caching).
  • The server either returns "200 OK" with a resource document, "304 Not Modified" with no content, or 4xx or 5xx with an error text.
Client                                     Server
  |                                           |
  |  1.) GET to Resource URI                  |
  |------------------------------------------>|
  |                                           |
  |  2.) 200 Ok                               |
  |      Resource representation              |
  |<------------------------------------------|
  |                                           |

This is the general form of an unconditional client HTTP request to retrieve a resource, with the server response. We ignore standard HTTP headers and we assume we're using XML rather than JSON:

Client:
-------------------------------------------------
GET /{resource uri} HTTP/1.1

Server:
-------------------------------------------------
HTTP/1.1 200 OK
Content-Type: application/{schema}+xml
Date-Modified: {resource date and time}
ETag: {resource entity tag}

<?xml version="1.0"?>
<{schema} xmlns="http://www.restms.org/schema/{schema}">
  <{resource type} ...>
    {resource contents}
  </{resource type}>
</{schema}>

The server may return these response codes specifically for a GET request:

  • 200 OK - the resource already existed as specified (only for public resources).
  • 304 Not Modified - the client already has the latest copy of the resource.
  • 400 Bad Request - the resource document was incomplete or badly formatted.

In case of a 4xx or 5xx error response the server will return a textual error message in the content body of the response. The client should be able to handle all normal HTTP errors, such as "401 Unauthorized", "404 Not Found", "413 Too Large", "500 Internal Error", and so on.

Conditional retrieval is used to cache resources and fetch them only if they have changed. Clients retrieve resources conditionally as follows:

  • The client must previously have retrieved the resource.
  • The client does a GET method with If-None-Match: and If-Modified-Since: headers.
  • The server returns "200 OK" and the resource document if the client's copy is out of date.
  • The server returns "304 Not Modified" with no content if the client's copy is up-to-date.

This is the general form of a client HTTP request to conditionally retrieve a resource:

Client:
-------------------------------------------------
GET /{resource uri} HTTP/1.1
If-None-Match: {resource entity tag}
If-Modified-Since: {resource date and time}

A conditional get only takes effect if there were no other errors, i.e. if the result would otherwise be "200 OK". It is valid to send either of the If-None-Match: or If-Modified-Since: headers but for best results, use both.

Retrieving a resource has no side effects, i.e. repeated requests to retrieve the same resource will provoke the same responses, unless a third party deletes or modifies the resource.

Updating a resource

Clients update resources through the API as follows:

  • The client must know the URI of the resource that it wants to update.
  • The client should have retrieved the resource before updating it.
  • The client sends a PUT method to the resource URI with the modified resource document.
  • The client optionally specifies headers to do a conditional update.
  • The server either returns 2xx with a resource document, or 4xx or 5xx with an error text.
Client                                     Server
  |                                           |
  |  1.) GET to Resource URI                  |
  |------------------------------------------>|
  |                                           |
  |  2.) 200 OK                               |
  |      Resource representation              |
  |<------------------------------------------|
  |                                           |
  |  3.) PUT to Resource URI                  |
  |      Modified resource representation     |
  |------------------------------------------>|
  |                                           |
  |  4.) 200 OK                               |
  |<------------------------------------------|

This is the general form of a client HTTP request to unconditionally modify a resource, with the server response. We ignore standard HTTP headers and we assume we're using XML rather than JSON:

Client:
-------------------------------------------------
PUT /{resource uri} HTTP/1.1
Content-Type: application/{schema}+xml

<?xml version="1.0"?>
<{schema} xmlns="http://www.restms.org/schema/{schema}">
  <{resource type} ...>
    {resource contents}
  </{resource type}>
</{schema}>

Server:
-------------------------------------------------
HTTP/1.1 200 OK
Date: {response date}

The server may return these response codes specifically for a PUT request:

  • 200 OK - the resource was successfully updated.
  • 204 No Content - the client provided no resource document and the update request had no effect.
  • 400 Bad Request - the resource document was incomplete or badly formatted.
  • 403 Forbidden - the PUT method is not allowed on the resource.
  • 412 Precondition Failed - the client does not have the latest copy of the resource.

In case of a 4xx or 5xx error response the server will return a textual error message in the content body of the response. The client should be able to handle all normal HTTP errors, such as "401 Unauthorized", "404 Not Found", "413 Too Large", "500 Internal Error", and so on.

Conditional update is used to detect and prevent update conflicts (when multiple clients try to update the same resource at the same time). Clients conditionally update resources conditionally as follows:

  • The client must previously have retrieved the resource.
  • The client does a DELETE method with If-Match: and If-Unmodified-Since: headers.
  • The server returns "412 Precondition Failed" if the client's copy is out of date.
  • The server returns "200 OK" and the new resource document if the client's copy was up-to-date.

This is the general form of a client HTTP request to conditionally update a resource:

Client:
-------------------------------------------------
PUT /{resource uri} HTTP/1.1
If-Match: {resource entity tag}
If-Unmodified-Since: {resource date and time}

A conditional PUT only takes effect if there were no other errors, i.e. if the result would otherwise be "200 OK". It is valid to send either of the If-Match: or If-Unmodified-Since: headers but for best results, use both.

Modifying resources is idempotent, i.e. repeated requests to modify the same resource are allowed, and safe, unless a third party modifies or deletes the resource.

Deleting a resource

Clients delete resources through the API as follows:

  • The client must know the URI of the resource that it wants to delete.
  • The client should have retrieved the resource before delete it.
  • The client sends a DELETE method to the resource URIt.
  • The client optionally specifies headers to do a conditional delete.
  • The server either returns "200 OK", or 4xx or 5xx with an error text.
Client                                     Server
  |                                           |
  |  1.) GET to Resource URI                  |
  |------------------------------------------>|
  |                                           |
  |  2.) 200 OK                               |
  |      Resource representation              |
  |<------------------------------------------|
  |                                           |
  |  3.) DELETE to resource URI               |
  |------------------------------------------>|
  |                                           |
  |  4.) 200 OK                               |
  |<------------------------------------------|
  |                                           |

This is the general form of a client HTTP request to unconditionally delete a resource, with the server response. We ignore standard HTTP headers:

Client:
-------------------------------------------------
DELETE /{resource uri} HTTP/1.1

Server:
-------------------------------------------------
HTTP/1.1 200 OK

The server may return these response codes specifically for a DELETE request:

  • 200 OK - the resource was successfully updated.
  • 403 Forbidden - the DELETE method is not allowed on the resource.
  • 412 Precondition Failed - the client does not have the latest copy of the resource.

In case of a 4xx or 5xx error response the server will return a textual error message in the content body of the response. The client should be able to handle all normal HTTP errors, such as "401 Unauthorized", "404 Not Found", "413 Too Large", "500 Internal Error", and so on.

Conditional delete is used to detect and prevent delete conflicts (when multiple clients try to delete the same resource at the same time). Clients conditionally delete resources conditionally as follows:

  • The client must previously have retrieved the resource.
  • The client does a DELETE method with If-Match: and If-Unmodified-Since: headers.
  • The server returns "412 Precondition Failed" if the client's copy is out of date.
  • The server returns "200 OK" if the client's copy was up-to-date.

This is the general form of a client HTTP request to conditionally delete a resource:

Client:
-------------------------------------------------
DELETE /{resource uri} HTTP/1.1
If-Match: {resource entity tag}
If-Unmodified-Since: {resource date and time}

A conditional DELETE only takes effect if there were no other errors, i.e. if the result would otherwise be "200 OK". It is valid to send either of the If-Match: or If-Unmodified-Since: headers but for best results, use both.

Deleting resources is idempotent, i.e. repeated requests to delete the same resource are allowed, and safe. Implementations may cache the URIs of deleted resources in order to differentiate between deletes on already-deleted resources, and deletes on resources that never existed.

If the resource to be deleted contains other resources, these are implicitly and silently deleted along with the resource.

MIME types

When the client retrieves a resource it MAY specify which MIME type it desires using the Accept header. While the HTTP specification (RFC 2616 section 14.1[5]) defines a complex format for the Accept header, RestTL allows these three possibilities:

  • "Accept: application/{schema}+xml"
  • "Accept: application/{schema}+json"
  • "Accept: text/xml", which is equivalent to no Accept: header.

The server will respond with a resource document in the requested format and a Content-Type: header of the appropriate type. Note that most browsers will display "text/xml" documents as XML, while they will not show "application/{schema}+xml". Thus it is possible to embed RestTL resource URIs in, for example, HTML documents, with usable results.

When a client creates a new resource or modifies an existing resource, it SHOULD specify the MIME type of the resource document that it is sending to the browser, using the Content-Type header. RestTL allows the same three values as for the Accept: header:

  • "Content-Type: application/{schema}+xml"
  • "Content-Type: application/{schema}+json"
  • "Content-Type: text/xml", which is equivalent to no Content-Type: header.

When a client deletes a resource neither the Accept: nor Content-Type: headers have any significance, and MUST be ignored by the server.

If a server does not support the content type requested or provided by the client, it SHOULD return "501 Not Implemented."

Asynchronous retrieval

HTTP is generally a synchronous protocol in which a client polls a server for resources. This is undesirable in many architectures, both from a design and a performance perspective. RestTL allows three mechanisms for asynchronous non-polled resource delivery. In each case, the client sends a GET to the server, which responds only when some condition (an event) is true. Some sources call this "long polling".

The three asynchronous delivery mechanisms are:

  1. Streaming, in which a resource is delivered in segments, over time. RestTL has no specific support for streaming: it is implemented using multipart contents, but otherwise looks like a conventional resource GET.
  2. Creation notification, in which a resource is delivered only when it is created. RestTL implements this using "asynclets".
  3. Update notification, in which a resource is delivered only when it is changed. RestTL implements this using the custom When-Modified-After: and When-None-Match: headers.

Creation notification via asynclets

An asynclet is an "asynchronous resource instance", which is a resource that is given a URI identifier before it exists. When the client retrieves the asynclet, the server will respond only when the resource has come into existence.

Asynclets are used in a specific case: when resources sit in some kind of a queue that is retrieved and emptied by the client (using GET and DELETE in a loop). The queue would be the parent resource, the container. The queue then contains zero or more existing resources plus a single asynclet.

A normal resource is identified in a parent resource by a href attribute, and other attributes:

<some-type href="some-URI" ... />

An asynclet has the href attribute and a second attribute 'async="1"', telling the client that this resource, though it has a URI, does not in fact yet exist:

<some-type href="some-URI" async="1" />

When the client retrieves an asynclet, the server waits until the resource is created, within that parent, and it then responds to the client with the contents of that new resource.

When the client retrieves the asynclet container, the container resource holds all existing resources plus a single asynclet:

<some-type href="some-URI-1" ... />
    <some-type href="some-URI-2" ... />
    <some-type href="some-URI-3" ... />
    <some-type href="some-URI-4" ... />
    <some-type href="some-URI-5" async="1" />

At any time a new resource may 'arrive' and the URI held by a client for an asynclet will then refer to a real existing resource. This is transparent to the client except that there will be no wait when the client issues a GET on that URI.

Update notification

Applications can monitor specific resources for updates using two HTTP extension headers. If the client has already retrieved the resource it specifies the resource ETag:

Client:
-------------------------------------------------
GET /{resource uri} HTTP/1.1
When-None-Match: {resource entity tag}

The client can also specify the last-known modified date and time, the current date and time, or a later date and time:

Client:
-------------------------------------------------
GET /{resource uri} HTTP/1.1
When-Modified-After: {resource date and time}

The server will respond with the new resource document when it is modified. The client should be able to handle any HTTP error condition, such as "404 Not Found" or "501 Not Implemented". If both headers are specified, the server will respond only when both conditions are true.

The When-Modified-After: header was originally proposed in the Comet[3] specification.

Caching and ETags

RestTL assumes that all resources may be cached. We define two types of cache. First, the "end cache", is held in the browser or HTTP client layer. Second, the "proxy cache" is a service that sits between the client and the server.

The server can disallow (or at least discourage) both types of cache from holding content. It does this by adding a "Cache-Control: No-cache" header to the response.

The client can inform the server or proxy cache that it has cacheable content for a resource by specifying either one of, or both of, the If-Modified-Since and If-None-Match header together with an ETag. Usually, specifying both conditional headers gives best results.

ETags are calculated by the server. The ETag value for resources that can have multiple MIME representations MUST depend on the MIME type of the returned resource specification. Thus a resource returned as XML will have a different ETag than the same resource returned as JSON.

Note that if a proxy cache is enabled, clients will not be guaranteed to receive the freshest version of a resource for a GET method. There is no mechanism to push resource updates to proxy servers.

Idempotency and side-effects

The GET, PUT, and DELETE methods are idempotent: the client can safely issue these more than once. POST is idempotent when creating public resources. POST to create private resources is not idempotent and will create one resource per successful execution.

Idempotency allows the client to safely recover from failures where it did not get a response, yet could not sure the server did not receive the request. For example, any failure in the network, the client, or an intermediary that happens after the server receives the request but before the client receives the response. The client recovers by simply reissuing any GET, PUT, DELETE, and POST-public requests that were not completed.

The GET method does not modify the state of any resource on the server.

Pipelining

The client may send requests in parallel, which is called "pipelining". RFC 2616[5] section 8.1.2.2 says,

Clients SHOULD NOT pipeline requests using non-idempotent methods or non-idempotent sequences of methods (see section 9.1.2). Otherwise, a premature termination of the transport connection could lead to indeterminate results. A client wishing to send a non-idempotent request SHOULD wait to send that request until it has received the response status for the previous request.

RestTL clients MAY pipeline GET, PUT, DELETE and POST-public methods, but SHOULD NOT pipeline POST-private methods.

Error responses

When the server returns an error response (4xx or 5xx), the content body MUST be in plain text, and the MIME type MUST be "text/plain". The client can print and log the content body as a text with no parsing or decoding.

RestTL resource document grammar

Most, though not all, resources managed through a RestTL API are represented as structured resource documents.

In generally, a client sends a resource document to the server when it wishes to create a new resource or update a resource. The server sends a resource document to the client in response to a create, retrieve, or update request. Certain resources may be represented as opaque MIME-type blobs, in which case they are posted and retrieved as such, not as structured resource documents.

RestTL resource documents have a schema-independent regular grammar designed to support all the requirements of a RESTful API. The grammar makes it possible for applications to navigate the API as follows:

  • Resources are typed, and the type names form the main element names in the document.
  • A resource type may be a container for other resource types.
  • This hierarchy of resource types forms a static type tree attached to a single root type.
  • At runtime, the actual resources form a dynamic resource tree attached to a single root resource.
  • Clients navigate the resource tree by retrieving the root resource.
  • Resource documents may contain URI references to accessible child resources.
  • A private resource is accessible only to the client that created it, and knows its URI.

Our goals with this design are:

  • To define a document syntax that is easily mapped to arbitrary structured languages including XML and JSON.
  • To provide documents that are navigable and discoverable with mimimum prior knowledge.
  • To deliver the cheap parsing benefits of structured languages without the cost of formal validation.
  • To allow unilateral extensibility of the resource hierarchy by server implementations.
  • To keep things as simple as possible for RestTL application developers.
  • To allow for future evolution in structured data representation.

Basic syntax rules

RestTL resource documents obey these basic rules:

  • All resource documents in an API are part of a schema that defines the type tree.
  • The resource document has a document root element with the name of the schema.
  • The document root contains zero or more resource roots.
  • The resource root elements may contain other elements.
  • All elements except the document root correspond to RestTL resources, with the name of the element equal to the resource type.
  • Resource properties are represented as element attributes, not as child elements.
  • All elements except the document root may repeat 0 or more times.

Further, for XML documents:

  • The Content-type MUST be "application/{schema-name}+xml".
  • The document root has a single attribute, xmlns="http://www.restms.org/schema/{schema-name}". Note that the schema does not need to exist.
  • The following character MUST be escaped in attribute values:
    • " (escaped by writing &quot;)

And for JSON documents:

  • The Content-type MUST be "application/{schema-name}+json".
  • The following character MUST be escaped in value strings:
    • " (escaped by writing \")

Here is an example of a RestTL document in XML, for a schema called "music":

<?xml version="1.0"?>
<music xmlns="http://www.restms.org/schema/music">
  <playlist name = "default">
    <album
      artist="Echobelly" title="On" released="1995-10-17"
      summary="Underrated, bittersweet guitar rock perfection">
      <track title="Car Fiction" length="2:31" />
      <track title="King of the Kerb" length="3:59" />
      <track title="Great Things" length="3:31" />
      <track title="Natural Animal" length="3:27" />
      <track title="Go Away" length="2:44" />
      <track title="Pantyhose and Roses" length="3:26" />
      <track title="Something Hot in a Cold Country" length="4:01" />
      <track title="Four Letter Word" length="2:51" />
      <track title="Nobody Like You" length="3:52" />
      <track title="In the Year" length="3:31" />
      <track title="Dark Therapy" length="5:30" />
      <track title="Worms and Angels" length="2:38" />
    </album>
  </playlist>
</music>

The resource tree for the music schema is:

playlist
    |
    o- album
        |
        o- track

Here is the same document in JSON:

{
"music": {
  "playlist": [ { "name":"default",
    "album": [ { "artist":"Echobelly", "title":"On", "released":"1995-10-17",
      "summary":"Underrated, bittersweet guitar rock perfection",
      "track": [
        { "title":"Car Fiction", "length":"2:31" },
        { "title":"King of the Kerb", "length":"3:59" },
        { "title":"Great Things", "length":"3:31" },
        { "title":"Natural Animal", "length":"3:27" },
        { "title":"Go Away", "length":"2:44" },
        { "title":"Pantyhose and Roses", "length":"3:26" },
        { "title":"Something Hot in a Cold Country", "length":"4:01" },
        { "title":"Four Letter Word", "length":"2:51" },
        { "title":"Nobody Like You", "length":"3:52" },
        { "title":"In the Year", "length":"3:31" },
        { "title":"Dark Therapy", "length":"5:30" },
        { "title":"Worms and Angels", "length":"2:38" }
      ] }
    ] }
  ] }
}

Note that it is possible to map between JSON and XML without loss. The key issue for XML documents is that properties are represented as element attributes, not as child elements.

Navigation and discovery

RestTL documents use the following rule to allow navigation and discovery:

  • The attribute "href", if present, holds the URI for the resource that the element represents.
  • The URI for the root resource is known to both client and server by common agreement.
  • The URIs for all non-root resources are generated by the server and may be stored by the client.
  • All URIs provided by the server are absolute. The client at the HTTP level should use URIs with no scheme or hostname.

Here is an example of a client retrieving a public playlist resource using a HTTP GET method, with the server's response. The server is at host.com:

Client:
-------------------------------------------------
GET /music/playlist/default HTTP/1.1

Server:
-------------------------------------------------
HTTP/1.1 200 OK
Content-Type: application/music+xml

<?xml version="1.0"?>
<music xmlns="http://www.restms.org/schema/music">
  <playlist name="default">
    <album
        artist="Echobelly" title="On"
        href="http://host.com/music/resource/A1023" />
    <album
        artist="Muse" title="Showbiz"
        href="http://host.com/music/resource/A0911" />
    <album
        artist="Toumani Diabate" title="Djelika"
        href="http://host.com/music/resource/A0023" />
  </playlist>
</music>

To retrieve a specific album, the client uses the URI provided by the server, for example:

Client:
-------------------------------------------------
GET /music/resource/A1023 HTTP/1.1

Server:
-------------------------------------------------
HTTP/1.1 200 OK
Content-Type: application/music+xml

<?xml version="1.0"?>
<music xmlns="http://www.restms.org/schema/music">
    <album
        artist="Echobelly" title="On" released="1995-10-17"
        summary="Underrated, bittersweet guitar rock perfection"
      <track title="Car Fiction" length="2:31"
        href="http://host.com/music/resource/A1023/1" />
      <track title="King of the Kerb" length="3:59"
        href="http://host.com/music/resource/A1023/2" />
      <track title="Great Things" length="3:31"
        href="http://host.com/music/resource/A1023/3" />
      <track title="Natural Animal" length="3:27"
        href="http://host.com/music/resource/A1023/4" />
      <track title="Go Away" length="2:44"
        href="http://host.com/music/resource/A1023/5" />
      <track title="Pantyhose and Roses" length="3:26"
        href="http://host.com/music/resource/A1023/6" />
      <track title="Something Hot in a Cold Country" length="4:01"
        href="http://host.com/music/resource/A1023/7" />
      <track title="Four Letter Word" length="2:51"
        href="http://host.com/music/resource/A1023/8" />
      <track title="Nobody Like You" length="3:52"
        href="http://host.com/music/resource/A1023/9" />
      <track title="In the Year" length="3:31"
        href="http://host.com/music/resource/A1023/10" />
      <track title="Dark Therapy" length="5:30"
        href="http://host.com/music/resource/A1023/11" />
      <track title="Worms and Angels" length="2:38"
        href="http://host.com/music/resource/A1023/12" />
    </album>
</music>

To retrieve a specific track, the client once again uses the URI provided by the server. Note that in this case the server delivers a content of type "audio/mpeg-3", which the client should process accordingly (and not as RestTL XML or JSON):

Client:
-------------------------------------------------
GET http://host.com/music/resource/A1023/5 HTTP/1.1

Server:
-------------------------------------------------
HTTP/1.1 200 OK
Content-Length: 2870112
Content-Type: audio/mpeg-3

...opaque binary content...

Handling unknown elements

Resource documents may contain elements, and unknown attributes on known elements. This is especially likely when the client and server implement different versions of the API, or if the API is extended by a particular client or server implementatoin.

Clients and servers should tolerate and ignore unknown elements. Neither the client nor the server should maintain unknown elements.

Bibliography
1. Roy Fielding, "Representational State Transfer (REST)" www.ics.uci.edu
2. "The Atom Syndication Format" - ietf.org
3. "A Standards Based Approach to Comet Communication with REST" cometdaily.com
4. "Key words for use in RFCs to Indicate Requirement Levels" - ietf.org
5. "HTTP/1.1 Protocol Parameters" - http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html w3.org]

Edit | Files | Tags | Source | Print | Talk

Use the Talk page to discuss this specification.

Use one of these tags to define the specification's state:

  • raw - new specification
  • draft - has at least one implementation.
  • stable - has been deployed to real users.
  • legacy - is being replaced by newer specifications.
  • retired - has been replaced and is no longer used.
  • deleted - abandoned before becoming stable.