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
- See the AtomServer Protocol
Reference for detailed information about the XML format.
- See the
Atom Publishing Protocol Reference for further information about
the
elements of the feed itself.
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
- URL Structure
- Examples
- Requesting a feed for the first time
- Requesting a feed after the first time
- Requesting a "paging" feed
- Requesting a specific entry.
- Inserting a new entry
- Updating an entry
- Deleting an entry
- Additional resources
URL structure
An AtomServer URI has the form;/{version}/{workspace}/{collection}/{id}/{revision}
- {version} is the version of this AtomServer server. This is a placeholder in case future versions of your Service have to change substantially.
- {workspace}
is the Atom Workspace.
- {collection} is the Atom Collection.
- {id}
is the identifier for the desired Atom representation. If id is
omitted, then it is assumed that the client intends to operate on the
entire collection. The id may be any String up to 32 characters in
length.
- {revision}
is the identifier for the desired revision. It is used
for optimistic concurrency and is only required in certain
circumstances (PUTs and DELETEs) See the
Protocol Reference document
for further information.
/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;/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
- locale is the "locale" (language and country identifier). It must be specified in the required format.
- updated-min is the last modified date. It must be specified in required Atom format.
- start-index is the "start index" for the requested page.
- max-results is the "page size" for the requested page
- entry-type indicates the type of Entry to return. This parameter is generally not required.
Examples
Notes pertaining to all of the examples;- The responses shown below have been formatted to make them easy to read. Atom actually responds without the additional whitespace!
- The Atom namespace is assumed, so none of the XML tags are shown with atom: prefix.
- The actual Entry XML is not shown.
That is out of scope for
this document.
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 CollectionGET
/v1/widgets/{collection}
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- You can set the If-Modified-Since HTTP Header of your request to the previous updated date, which reflects the last time you requested a feed.
- You can use the updated-min
URL Query parameter. (e.g.
GET /v1/widgets/acme?updated-min=2007-10-05T19:17:42.750Z) which
behaves identical to the
If-Modified-Since Header. Note, the date provided must be formatted according to the
Atom specification (see here).
- Or best of all, you can use the start-index URL Query (e.g. GET /v1/widgets/acme?start-index=153). Using this method ensures that you will never recieve any inappropriate duplicate Entries. The reason for this is that a "last modified date" operation is, by definition, an inclusive operation (i.e. ">="). And that many Entries could possibly have the same Date. To work around this, AtomServer indexes every Entry monotonically. And a "get next index" operation is exclusive (i.e. ">"), so you are therefore be assured of getting the appropriate next Entry.
HTTP
Header
If-Modified-Since: 2007-10-05T19:17:42.750Z
GET /v1/widgets/acme
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>
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 thisGET
/v1/widgets/acme?max-results=2
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&max-results=2" rel="next" />
<link href="/myserver/v1/widgets/acme?start-index=0&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>
<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
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
- The actual Widget XML is not shown in this example. It is immaterial. Although do note that the entire XML document is returned inside the content element.
- One can request the Entry using the revision (i.e. /v1/widgets/acme/169371.en_US.xml/0 ),
but if the revision is not available you will receive a 409 Conflict error. And
if you do receive a 409 Conflict,
you will receive the response content as described in the Update section below.
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.- Using a PUT request. If you already know the identifier of your Entry, when it was assigned outside of AtomServer, you make a PUT request to the specific URL associated with this Entry.
- Using a POST request. If you want
AtomServer to assign an Entry ID for you, then you make a POST request
to the Feed URL of the Workspace, Collection you want this Entry
created in.
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>
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>
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>
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>
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>
<?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>
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
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>
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)