logo   AtomServer, Protocol Basics


Chris Berry, Bryon Jacob. Updated 05/01/08


This document describes the basics of the protocol used by AtomServer, including examples of what requests looks like, what results look like, and so on. It is intended for anyone wanting to understand the general idea of the XML format and protocol used by AtomServer.

For a detailed description of the actual protocol, either
This document does not explain the underlying concepts behind AtomServer; REST, Atom, and OpenSearch. That information can be found in the AtomServer General Introduction document. It is highly recommended that you read this document first.

Nor does this document explain the basics of XML, namespaces, syndicated feeds, and the GET, POST, PUT, and DELETE requests in HTTP, as well as HTTP's concept of a "resource." For more information about those things, see the Additional resources section of this document.

This document doesn't rely on any particular programming language; you can send and receive AtomServer messages using any programming language that lets you issue HTTP requests and parse XML-based responses.

Finally, giving credit where it is due, this document is based on the GData Protocol Basics document.

Contents

  1. URL Structure
  2. Examples
    1. Requesting a feed for the first time
    2. Requesting a feed after the first time
    3. Requesting a "paging" feed
    4. Requesting a specific entry.
    5. Inserting a new entry
      1. Inserting a new Entry using a POST
      2. Inserting a new Entry using a PUT
    6. Updating an entry
    7. Deleting an entry
  3. Additional resources

URL structure

An AtomServer URI has the form;

/{version}/{workspace}/{collection}/{id}/{revision}

where
The following are examples of valid AtomServer URIs;

/v1/widgets/acme
/v1/widgets/acme?locale=fr
/v1/widgets/acme?updated-min=2007-06-22T20:38:49.000Z&locale=en_GB&max-results=20
/v1/widgets/acme/2888
/v1/widgets/acme/2888?locale=fr
/v1/widgets/acme/2888.en.xml/3

The following URL query parameters are recognized;
See the Protocol Reference document for further, important information on specifying these parameters.

Examples

Notes pertaining to all of the examples;

1) Requesting a feed for the first time

The general form of the AtomServer feed request URL follows, where v1 is the version Id, and {collection} specifies the Atom Collection

GET /v1/widgets/{collection} 

Let's assume that you are requesting the feed for the acme Collection, that this is your first request for this feed, and, for the sake of brevity, that the feed has only two Entries associated with it.
To see it, you would send the following request to the server:

GET /v1/widgets/acme

The server responds:

200 OK
<?xml version='1.0' encoding='UTF-8'?>
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:ha="https://atomserver.org/namespaces/1.0/" xmlns:os="http://a9.com/-/spec/opensearchrss/1.1/">
<as:endIndex>153</as:endIndex>
<link href="/myserver/v1/widgets/acme" rel="self" />
<author><name>AtomServer APP Service</name></author>
<title type="text">acme entries</title>
<updated>2007-10-05T19:17:42.750Z</updated>
<id>tag:atomserver.org,2007:v1:acme</id>
<entry>
<id>/myserver/v1/widgets/acme/205390.en.xml</id>
<updated>2007-10-05T19:17:42.750Z</updated>
<published>2007-10-05T18:48:23.437Z</published>
<title type="text"> Entry: acme 205390.en</title><author>
<name>AtomServer Atom Service</name></author>
<link href="/myserver/v1/widgets/acme/205390.en.xml" rel="self" />
<link href="/myserver/v1/widgets/acme/205390.en.xml/2" rel="edit" />
<link href="/myserver/v1/widgets/acme/205390.en.xml" rel="alternate" />
</entry>
<entry>
<id>/myserver/v1/widgets/acme/205391.en.xml</id>
<updated>2007-10-05T18:48:23.437Z</updated>
<published>2007-10-05T12:36:23.437Z</published>
<title type="text"> Entry: acme 205391.en</title><author>
<name>AtomServer Atom Service</name></author>
<link href="/myserver/v1/widgets/acme/205391.en.xml" rel="self" />
<link href="/myserver/v1/widgets/acme/205391.en.xml/1" rel="edit" />
<link href="/myserver/v1/widgets/acme/205391.en.xml" rel="alternate" />
</entry>
</feed

Note that the feed has, as expected, two entry elements - one for each Widget in this example. Each of these entries contains a "permalink" to the specific resource associated with that Entry (e.g. /myserver/v1/widgets/acme/205390.en.xml). For AtomServer this may ultimately be either a physical XML file stored on disk, or XML stored in the database. The client (i.e. the feed reader) can follow these links as it sees fit. Although the client should always use the edit link when it wishes to modify the entry.

Had there been more than than 100 entries available (100 is the default entries per page limit), or you had specified the max-results query parameter, then several additional elements would have been returned by the feed. Please see the Paging Time-sensitive Feed section for further details.

Note also that the feed returns an updated tag and an endIndex tag. The feed reader should store one of these values and use it to control the amount of content it retrieves in subsequent reads. This is explained further in the next example.

Each entry also contains an updated tag. This tag represents the last modification date for the data represented by this resource. For AtomServer this is the actual system modification date for the Database row associated with this Entry.

Now, if you had wanted the French versions of this feed, you would make your request like this;

GET /v1/widgets/acme?locale=fr

And the server would have responded with a feed of the French versions. NOTE, if no French version had been available, then nothing would have been returned instead.

2) Requesting a feed after the first time

Continuing on with the first example, let's assume that Widget 205390 has been updated since you last requested the feed, and that you have stored either the updated date or the endIndex value from Example 1 someplace safe.  Most likely, what you want to see is only the updated entries and no others. To do this you have several choices
Other than that the request is identical to Example 1.

HTTP Header
  If-Modified-Since: 2007-10-05T19:17:42.750Z

GET /v1/widgets/acme

The server responds with:

200 OK
<?xml version='1.0' encoding='UTF-8'?>
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:ha="https://atomserver.org/namespaces/1.0/" xmlns:os="http://a9.com/-/spec/opensearchrss/1.1/">
<as:endIndex>154</as:endIndex>
<link href="/myserver/v1/widgets/acme" rel="self" />
<author><name>AtomServer APP Service</name></author>
<title type="text">acme entries</title>
<updated>2007-10-05T20:17:50.750Z</updated>
<id>tag:atomserver.org,2007:v1:acme</id>
<entry>
<id>/myserver/v1/widgets/acme/205390.en.xml</id>
<updated>2007-10-05T20:17:50.750Z</updated>
<published>2007-10-05T18:48:23.437Z</published>
<title type="text"> Entry: acme 205390.en</title><author>
<name>AtomServer Atom Service</name></author>
<link href="/myserver/v1/widgets/acme/205390.en.xml" rel="self" />
<link href="/myserver/v1/widgets/acme/205390.en.xml/3" rel="edit" />
<link href="/myserver/v1/widgets/acme/205390.en.xml" rel="alternate" />
</entry>
</feed>

If nothing had been updated since your last feed request, then you would have received:

304 NOT MODIFIED

Note that in thsi case, you did not simply receive an empty feed (i.e a feed with no entries). Instead you are returned the standard HTTP status code; 304 NOT MODIFIED.

3) A "paging" time-sensitive feed

In general, the feed will be returned to the client as a series of "pages".  An initial "paged" request looks like this

GET /v1/widgets/acme?max-results=2

The server responds with

200 OK
<?xml version='1.0' encoding='UTF-8'?>
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:ha="https://atomserver.org/namespaces/1.0/" xmlns:os="http://a9.com/-/spec/opensearchrss/1.1/">
<os:totalResults>65801</os:totalResults>
<os:startIndex>0</os:startIndex>
<os:itemsPerPage>2</os:itemsPerPage>
<as:endIndex>153</as:endIndex>
<link href="/myserver/v1/widgets/acme?start-index=153&amp;max-results=2" rel="next" />
<link href="/myserver/v1/widgets/acme?start-index=0&amp;max-results=2" rel="self" />
<author><name>AtomServer APP Service</name></author>
<title type="text">acme entries</title>
<updated>2007-10-05T19:17:42.750Z</updated>
<id>tag:atomserver.org,2007:v1:acme</id>
<entry>
<id>/myserver/v1/widgets/acme/205390.en.xml</id>
<updated>2007-10-05T18:48:23.437Z</updated>
<published>2007-10-05T18:48:23.437Z</published>
<title type="text"> Entry: acme 205390.en</title><author>
<name>AtomServer APP Service</name></author>
<link href="/myserver/v1/widgets/acme/205390.en.xml" rel="self" />
<link href="/myserver/v1/widgets/acme/205390.en.xml/2" rel="edit" />
<link href="/myserver/v1/widgets/acme/205390.en.xml" rel="alternate" />
</entry>
<entry>
<id>/myserver/v1/widgets/acme/205395.en.xml</id>
<updated>2007-10-05T15:48:56.437Z</updated>
<published>2007-10-05T12:50:76.437Z</published>
<title type="text"> Entry: acme 205395.en</title><author>
<name>AtomServer APP Service</name></author>
<link href="/myserver/v1/widgets/acme/205395.en.xml" rel="self" />
<link href="/myserver/v1/widgets/acme/205395.en.xml/1" rel="edit" />
<link href="/myserver/v1/widgets/acme/205395.en.xml" rel="alternate" />
</entry>
</feed>


Note that the response contains many new XML elements. If these elements are not present, then the client can assume the results are all on one page.

<os:totalResults> The total number of results available for this query (from the OpenSearch spec). Note that this number is "temporal". Because entries may be modified, and possibly even deleted, this number may grow as the client pages.
<os:startIndex>
The starting "index" for this page (from the OpenSearch spec). Note that this index should not be interpreted. It is valid to the Server, but the client should never attach any further meaning to the number. In other words, one can not use (startIndex + itemsPerPage) to determine the page next index
<os:itemsPerPage> The page size (from the OpenSearch spec).
<as:endIndex> The ending "index" for this page (an AtomServer extension). Note that this index should not be interpreted. It is valid to the Server, but the client should never attach any further meaning to the number. endIndex is required so that we can determine the next page.
<link href="/myserver/v1/widgets/acme?start-index=3264&max-results=2" rel="next" /> The "next link" (from the Paging History spec).  The client should always use this link to get to the next page.  It is the only guaranteed mechanism for page traversal.

4) Requesting a specific entry

The general form of the AtomServer Entry request URL follows, where v1 is the version Id, {collection} specifies the Atom Collection (e.g. acme, etc.),  {propId} specifies the Entry Id,  and {locale} specifies the language. Locale is optional, depending on how the Workspace or Collection is configured.

GET /v1/widgets/{brand}/{prodId}.{locale}.xml

Let's assume that you are requesting the US English version of the acme Widget; 169371.
To see it, you would send the following request to the server:

GET /v1/widgets/acme/169371.en_US.xml

The server responds with:

200 OK
<?xml version='1.0' encoding='UTF-8'?>
<entry xmlns="http://www.w3.org/2005/Atom">
<id>/myserver/v1/widgets/acme/169371.en_US.xml</id>
<updated>2007-10-05T19:17:42.640Z</updated>
<published>2007-10-05T19:17:42.640Z</published>
<title type="text"> Entry: acme 169371.en_US</title>
<author><name>AtomServer APP Service</name></author>
<link href="/myserver/v1/widgets/acme/169371.en_US.xml" rel="self" />
<link href="/myserver/v1/widgets/acme/169371.en_US.xml/0" rel="edit" />
<content type="application/xml">
<property xmlns="http://schemas.atomserver.org/widgets/v1/rev0" systemId="acme" id="2787" inNetwork="false">
.....
</property>
</content>
</entry

Notes:

5) Inserting a new entry

There are two ways to insert a new Entry. Which of these you use depends on whether you already know the Entry's identifier or not.

5.1) Inserting a new Entry using a POST

When you want AtomServer to create an Entry Id for you, you send a POST request to the appropriate Feed URL, and supply a new Entry in AtomServer format. AtomServer can be configured with an whatevre EntryIDGenerator you care to supply, as long as it supplies a unique Id for the given Workspace/Collection. By default, AtomServer uses a UUIDEntryIDGenerator, which creates a unique UUID as the Entry Id.

NOTE: If the Workspace and/or Collection has been configured for localization, then you must supply the locale Query parameter with the URL, as depicted in the example below.
NOTE: the XML namespace qualifier ( e.g. <entry xmlns="http://www.w3.org/2005/Atom">) is required by the Atompub specification!
NOTE: the client does not need to provide any of the entry elements when creating an Entry including the <id>.


POST /v1/widgets/acme?local=en_US
<entry xmlns="http://www.w3.org/2005/Atom">
<content type="application/xml">
<property xmlns="http://schemas.atomserver.org/widgets/v1/rev0" systemId="acme" inNetwork="false">
.....
</property>
</content>
</entry>

The server responds:

201 CREATED
<?xml version='1.0' encoding='UTF-8'?>
<entry xmlns="http://www.w3.org/2005/Atom">
<id>/myserver/v1/widgets/acme/a371412926e0439983eda36651049dfa.en_US.xml</id>
<updated>2007-10-05T19:17:42.640Z</updated>
<published>2007-10-05T19:17:42.640Z</published>
<title type="text"> Entry: acme a371412926e0439983eda36651049dfa.en_US</title>
<author><name>AtomServer APP Service</name></author>
<link href="/myserver/v1/widgets/acme/a371412926e0439983eda36651049dfa.en_US.xml" rel="self" />
<link href="/myserver/v1/widgets/acme/a371412926e0439983eda36651049dfa.en_US.xml/0" rel="edit" />
<content type="application/xml">
<property xmlns="http://schemas.atomserver.org/widgets/v1/rev0" systemId="acme" id="a371412926e0439983eda36651049dfa" inNetwork="false">
.....
</property>
</content>
</entry>

5.2) Inserting a new Entry using a PUT

When you already know the Entry Id for the Entry you want created, you send a PUT request to the appropriate Entry URL, and supply a new Entry in AtomServer format. Note that, for this case, there is effectively no difference between an Update and an Insert, except for Updates, where you must provide the revision identifier. (Although, for situations where there is a "single writer" and optimistic concurrency is not required, you can use the widcard revision identifier ( /* ) to override optimistic concurrency).

NOTE: the XML namespace qualifier ( e.g. <entry xmlns="http://www.w3.org/2005/Atom">) is required by the Atompub specification!
NOTE: the client does not need to provide any of the entry elements when creating an Entry except for <id>, which must be provided

PUT /v1/widgets/acme/169371.en_US.xml
<entry xmlns="http://www.w3.org/2005/Atom">
<id>/myserver/v1/widgets/acme/169371.en_US.xml</id>
<content type="application/xml">
<property xmlns="http://schemas.atomserver.org/widgets/v1/rev0" systemId="acme" id="2787" inNetwork="false">
.....
</property>
</content>
</entry>

The server responds:

201 CREATED
<?xml version='1.0' encoding='UTF-8'?>
<entry xmlns="http://www.w3.org/2005/Atom">
<id>/myserver/v1/widgets/acme/169371.en_US.xml</id>
<updated>2007-10-05T19:17:42.640Z</updated>
<published>2007-10-05T19:17:42.640Z</published>
<title type="text"> Entry: acme 169371.en_US</title>
<author><name>AtomServer APP Service</name></author>
<link href="/myserver/v1/widgets/acme/169371.en_US.xml" rel="self" />
<link href="/myserver/v1/widgets/acme/169371.en_US.xml/0" rel="edit" />
<content type="application/xml">
<property xmlns="http://schemas.atomserver.org/widgets/v1/rev0" systemId="acme" id="2787" inNetwork="false">
.....
</property>
</content>
</entry>

6) Updating an entry

To update an existing entry, use PUT, with the entry's edit URI (as provided by the server in the previous example, in the <link rel="edit"> element). Note that there is effectively no difference between an Update and an Insert, except in Updates, you must provide the revision identifier. Although, for situations where there is a "single writer" and optimistic concurrency is not required, you can use the wildcard revision identifier ( /* ) to override optimistic concurrency.

NOTE: the XML namespace qualifier ( e.g. <entry xmlns="http://www.w3.org/2005/Atom">) is required by the Atompub specification!

If your firewall does not allow PUT, then do an HTTP POST and set the method override header as follows:

X-HTTP-Method-Override: PUT

PUT the following

PUT /v1/widgets/acme/169371.en_US.xml/3
<entry xmlns="http://www.w3.org/2005/Atom">
<id>/myserver/v1/widgets/acme/169371.en_US.xml</id>
<content type="application/xml">
<property xmlns="http://schemas.atomserver.org/widgets/v1/rev0" systemId="acme" id="2787" inNetwork="false">
.....
</property>
</content>
</entry>

The server responds:

200 OK
<?xml version='1.0' encoding='UTF-8'?>
<entry xmlns="http://www.w3.org/2005/Atom">
<id>/myserver/v1/widgets/acme/169371.en_US.xml</id>
<updated>2007-10-05T19:17:42.640Z</updated>
<published>2007-10-05T19:17:42.640Z</published>
<title type="text"> Entry: acme 169371.en_US</title>
<author><name>AtomServer APP Service</name></author>
<link href="/myserver/v1/widgets/acme/169371.en_US.xml" rel="self" />
<link href="/myserver/v1/widgets/acme/169371.en_US.xml/4" rel="edit" />
<content type="application/xml">
<property xmlns="http://schemas.atomserver.org/widgets/v1/rev0" systemId="acme" id="2787" inNetwork="false">
.....
</property>
</content>
</entry>

Note that you receive an edit link and a self link in the response.  And that you must use this edit link when you wish to edit (Update or Delete) the Entry.

If you had requested a revision which did not match the Entry's revision currently in the AtomServer store, then you will receive a 409 Conflict error response like that below.

409 CONFLICT

<?xml version='1.0' encoding='UTF-8'?>
<a:error xmlns:a="http://incubator.apache.org/abdera">
   <a:code>409</a:code>
   <a:message>Optimistic Concurrency Error:: /myserver/v1/widgets/acme/12345.en.xml/2</a:message>
   <link xmlns="http://www.w3.org/2005/Atom" href="/myserver/v1/widgets/acme/12345.en.xml/3" rel="edit" />
</a:error>

Note that you also receive an edit link in the error response which you can use to make your update request again.

Further details on the optimistic concurrency model can be found here.

7) Deleting an entry

To delete an existing Entry, send a DELETE request, using the Entry's edit URI (as provided by the server in the previous example). Note that a special <deletion> XML document is returned as the XML content for DELETEs. This allows you to verify that a particular Entry has been deleted. Note that this XML content replaces the XML stored for this Entry. And thus, any subsequent Feed will return a <deletion> and the Feed client can act accordingly.  Deletions are configured by default to be verbose, which means that when an entry is deleted, the <deletion> XML element contains the content of the entry at the time just before it was deleted.  This is particularly useful if a client needs to take some action based on another object that is linked through a property of the deleted entry itself. 

If your firewall does not allow DELETE, then do an HTTP POST and set the method override header as follows:

X-HTTP-Method-Override: DELETE

The following example deletes an entry:

DELETE /v1/widgets/acme/205390.en.xml/3

The server responds:

200 OK
<?xml version='1.0' encoding='UTF-8'?>
<entry xmlns="http://www.w3.org/2005/Atom">
<id>/myserver/v1/widgets/acme/205390.en.xml</id>
<updated>2007-10-05T18:48:23.437Z</updated>
<published>2007-10-05T18:48:23.437Z</published>
<title type="text"> Entry: acme 205390.en</title>
<author><name>AtomServer Atom Service</name></author>
<link href="/myserver/v1/widgets/acme/205390.en.xml" rel="self" />
<link href="/myserver/v1/widgets/acme/205390.en.xml/4" rel="edit" />
<content type="application/xml">
<deletion xmlns="http://schemas.atomserver.org/atomserver/v1/rev0" collection="acme" id="205390" locale="en" workspace="widgets">
<property xmlns="http://schemas.atomserver.org/widgets/v1/rev0" systemId="acme" id="2787" inNetwork="false">
.....
</property>
</deletion>
</content>
<category />
</entry>

If the deletion fails, then the server responds with an error code.

Additional resources

You may find the following third-party documents useful:

    * Overview of Atom from IBM
    * HTTP 1.1 method definitions; specification for GET, POST, PUT, and DELETE
    * HTTP 1.1 status code definitions
    * Atom Syndication Reference (from Atom-enabled)
    * Getting to know the Atom Publishing Protocol (from IBM)