W3C Annotea

Annotea Protocols

An Annotea capable client, such as Amaya, interacts with annotation servers using HTTP. We distinguish five types of client-server interactions:

We use the standard HTTP POST protocol for storing a new annotation to the annotation server and HTTP GET protocol for fetching the annotations and returning the result to the client. POST provides the necessary interface for the server to construct a URI for the new annotation and return that URI to the client. When the client has the URI for a previously created annotation, it can (with the proper permissions) use HTTP PUT to modify the annotation and HTTP DELETE to delete an annotation.

In the examples shown here we use the URI http://annotea.example.org/annot to refer to an instance of an annotation service.

Posting a new annotation

To create a new annotation, the client posts some RDF describing the annotation to a selected annotation server. Both the annotation and its body are specified as anonymous RDF resources in the POST message. The server is responsible for allocating the URIs for them. If the body already exists, as will happen if the annotation body is another document that the user wants to use as an annotation, the URI of that existing document can be specified in the RDF when the annotation is posted.

In Figure 1 we illustrate a request to create a simple annotation using an existing document as the body of the annotation.

POST /annot HTTP/1.1
Host: annotea.example.org
Content-Type: application/xml
Content-Length: 636

<r:RDF xmlns:r="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
       xmlns:a="http://www.w3.org/2000/10/annotation-ns#"
       xmlns:d="http://purl.org/dc/elements/1.1/">
 <r:Description>
  <r:type resource="http://www.w3.org/2000/10/annotation-ns#Annotation"/>
  <r:type resource="http://www.w3.org/2000/10/annotationType#Comment"/>
  <a:annotates r:resource="http://example.com/some/page.html"/>
  <a:context r:resource='http://example.com/some/page.html#xpointer(id("Main")/p[2])'/>
  <d:creator>Ralph Swick</d:creator>
  <a:created>1999-10-14T12:10Z</a:created>
  <d:date>1999-10-14T12:10Z</d:date>
  <a:body r:resource="http://www.example.com/mycomment.html"/>
 </r:Description>
</r:RDF>

Figure 1: Creating an annotation with POST, using an existing document as the body.

Note that the resource http://www.example.com/mycomment.html is presumed to exist independently of this annotation.

A design issue we encountered is that we wanted to be able to use XML for describing the body of an annotation, and at the same time we wanted to be able to publish the complete annotation in a single HTTP transaction. In order to use XML in the body, the correct architectural approach is to store the body as a separate resource with its own content type. We therefore designed a simple packaging protocol that permits both the client and server to specify embedded HTTP message bodies. To do this, we declare an RDF namespace for describing certain HTTP headers and we specify those HTTP headers as normal RDF properties, as shown in Figure 2.

In Figure 2, we show the metadata that specifies an annotation of the page whose URI is http://example.com/some/page.html. The creator of this annotation is identified as "Ralph Swick". The text of the annotation body is "This is an important concept."

POST /annot HTTP/1.1
Host: annotea.example.org
Content-Type: application/xml
Content-Length: 1082

<r:RDF xmlns:r="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
       xmlns:a="http://www.w3.org/2000/10/annotation-ns#"
       xmlns:d="http://purl.org/dc/elements/1.1/"
       xmlns:h="http://www.w3.org/1999/xx/http#">
 <r:Description>
  <r:type resource="http://www.w3.org/2000/10/annotation-ns#Annotation"/>
  <r:type resource="http://www.w3.org/2000/10/annotationType#Comment"/>
  <a:annotates r:resource="http://example.com/some/page.html"/>
  <a:context r:resource='http://example.com/some/page.html#xpointer(id("Main")/p[2])'/>
  <d:creator>Ralph Swick</d:creator>
  <a:created>1999-10-14T12:10Z</a:created>
  <d:date>1999-10-14T12:10Z</d:date>
   <a:body>
    <r:Description>
     <h:ContentType>text/html</h:ContentType>
     <h:ContentLength>250</h:ContentLength>
     <h:Body r:parseType="Literal">
  <html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <title>Ralph's Annotation</title>
  </head>
  <body>
  <p>This is an <em>important</em> concept; see
    <a href="http://example.com/other/page.html">other page</a>.</p>
  </body>
  </html>
    </h:Body>
   </r:Description>
  </a:body>
 </r:Description>
</r:RDF>

Figure 2: Creating an annotation with POST.

As specified by the RDF model, the data we pass to the server in the POST is a set of statements describing properties of the new (and unnamed) annotation resource that we would like the server to create. In response to the POST (Fig. 3), a new annotation is created and the server assigns URIs. Now the server has created the URIs for the anonymous resources and they can be used by the browser. The value of the a:body property is a URI of the content of the annotation; in this case the server implementation chose to store the text in a separate location and give it its own URI.

HTTP/1.1 201 Created
Location: http://www.example.org/Annotation/3ACF6D754
Content-Type: application/xml
Content-Length: 404

<r:RDF xmlns:r="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
       xmlns:a="http://www.w3.org/2000/10/annotation-ns#"
       xmlns:d="http://purl.org/dc/elements/1.1/">
 <r:Description about="http://www.example.org/Annotation/3ACF6D754">
  <a:annotates r:resource="http://example.com/some/page.html"/>
  <a:body resource="http://www.example.org/Annotation/3ACF6D754text"/>
 </r:Description> 
</r:RDF>

Figure 3: Sample response when creating a new annotation.

With this little bit of ad hoc packaging we can have a POST method that explicitly creates two resources at the same message and a GET method that returns these same resources in one message. This packaging protocol has the additional advantage that it makes POST and GET of multiple resources an atomic operation; there is no window in which another client might modify the annotation body after the annotation properties have been returned but before the body is returned.

Querying an annotation server

An annotation server is queried for the URIs of annotations it may hold using the GET method. Since the client will most commonly wish to query for annotations that have an annotates property naming a specific page that the user may currently be viewing, a particular query parameter is designated to pass the URI of that page, as shown in Figure 4.

GET /annot?w3c_annotates=http://example.com/some/page.html HTTP/1.1
Host: annotea.example.org
Accept: application/xml

Figure 4: Querying an annotation server for annotations annotating http://example.com/some/page.html.

The query parameter w3c_annotates may be best thought of as an abbreviation for the longer property name http://www.w3.org/2000/10/annotation-ns#annotates; that is, this GET is a short-hand for a query that says "return the names of resources that are the subjects of RDF statements in which the predicate is http://www.w3.org/2000/10/annotation-ns#annotates and the object is http://example.com/some/page.html". The server responds to this GET request by returning RDF/XML describing the properties of each annotation that has an annotates relationship to the given URI. In the first release of our server implementation, we return all the properties of each annotation including the URI of the body resource. Figure 5 illustrates a typical response; in this case there is only one annotation for the specified page.

HTTP/1.1 200 OK
Content-Type: application/xml
Content-Length: 689

<r:RDF xmlns:r="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
       xmlns:a="http://www.w3.org/2000/10/annotation-ns#"
       xmlns:d="http://purl.org/dc/elements/1.1/">
 <r:Description about="http://www.example.org/Annotation/3ACF6D754">
  <r:type resource="http://www.w3.org/2000/10/annotation-ns#Annotation"/>
  <r:type resource="http://www.w3.org/2000/10/annotationType#Comment"/>
  <a:annotates r:resource="http://example.com/some/page.html"/>
  <a:context r:resource='http://example.com/some/page.html#xpointer(id("Main")/p[2])'/>
  <d:creator>Ralph Swick</d:creator>
  <a:created>1999-10-14T12:10Z</a:created>
  <d:date>1999-10-14T12:10Z</d:date>
  <a:body r:resource="http://www.example.com/mycomment.html"/>
 </r:Description>
</r:RDF>

Figure 5: A typical response to the query in Figure 4.

Downloading an annotation

An annotation is downloaded from an annotation server using the GET method and specifying the annotation URI, as returned in a query response (Fig. 6).

GET /Annotation/3ACF6D754 HTTP/1.1
Host: www.example.org
Accept: application/xml

Figure 6: Downloading a specific annotation.

The response to this GET will be as in Figure 5.

Updating an annotation

An existing annotation is updated using the PUT1 method, specifying the URI of the annotation we wish to update. For example, to update the annotation created in the messages illustrated in Figures 2 and 3 above, we might specify the message in Figure 7.

PUT /Annotation/3ACF6D754 HTTP/1.1
Host: www.example.org
Content-Type: application/xml
Content-Length: 657

<r:RDF xmlns:r="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
       xmlns:a="http://www.w3.org/2000/10/annotation-ns#"
       xmlns:d="http://purl.org/dc/elements/1.1/">
 <r:Description about="http://www.example.org/Annotation/3ACF6D754">
  <r:type resource="http://www.w3.org/2000/10/annotation-ns#Annotation"/>
  <r:type resource="http://www.w3.org/2000/10/annotationType#Example"/>
  <a:annotates r:resource="http://example.com/some/page.html"/>
  <a:context r:resource='http://example.com/some/page.html#xpointer(id("Main")/p[2])'/>
  <d:creator>Ralph Swick</d:creator>
  <a:created>1999-10-14T12:10Z</a:created>
  <d:date>1999-10-14T13:14Z</d:date>
  <a:body>
    ...
  </a:body>
 </r:Description>
</r:RDF>

Figure 7: Updating an annotation using PUT.

Deleting an annotation

An annotation is deleted using the DELETE method, specifying the URI of the annotation we wish to remove. For example, to delete the annotation created in the messages illustrated in Figures 2 and 3 above, we might specify the message in Figure 8.

DELETE /Annotation/3ACF6D754 HTTP/1.1
Host: www.example.org

HTTP/1.1 200 OK

Figure 8: Deleting an annotation using DELETE.

Customized queries using Algae

Users want to filter the annotations they see depending on what they are doing. For example, in order to unclutter a heavily annotated document, a user may want only to display annotations made by certain users, or attached to a part of the document, or that were modified in the past 24 hours, or that correspond to a combination of these filters. The filtering may be done locally on the annotations that were already downloaded from the server or remotely, by means of the query string that will be sent to the server. Some of the server queries are going to happen frequently and they can be offered through an easy graphical interface. Other, more complicated queries can be offered to expert users or applications related to semantic Web that want to utilize the annotation information as part of their queries.

We have adapted a form of query language syntax very similar to what is used in Algernon [Crawford90] because it was available to us from other prototyping work. This syntax uses triples in which place-holder variables are denoted by names beginning with a questionmark, such as ?a. The collect clause defines how to output the result of the query. For instance, the query in Figure 9 returns all the annotations attached to a certain document with their annotation URI (?a), the context (?context), the creator (?creator), the time created (?created), the date (?date) and their annotation content URI (?body).

(ask
     '((http://www.w3.org/1999/02/22-rdf-syntax-ns#type ?a
          http://www.w3.org/2000/10/annotation-ns#Annotation) 
       (http://www.w3.org/2000/10/annotation-ns#annotates ?a
          http://example.com/some/page.html)
       (http://www.w3.org/2000/10/annotation-ns#context ?a ?context)
       (http://purl.org/dc/elements/1.1/creator ?a ?creator)
       (http://www.w3.org/2000/10/annotation-ns#created ?a ?created)
       (http://purl.org/dc/elements/1.1/date ?a ?date)
       (http://www.w3.org/2000/10/annotation-ns#body ?a ?body)
      ) :collect '(?a ?context ?creator ?created ?date ?body))

Figure 9: A sample query to the database from the annotation server.

The answer to the query is shown in Figure 10. It can consist of one or more annotation objects or return that no annotations were found. This RDF is processed by the browser and transferred to a format that is presented to the user.

   <r:Description
    about="http://example.org/CGI/annot?annotation=/2000/05/08-18:04:55">
      <r:type
       resource="http://www.w3.org/2000/10/annotation-ns#Annotation" />
      <a:annotates
       r:resource="http://example.com/some/page.html" />
      <a:context r:resource='http://example.com/some/page.html#xpointer(id("Main")/p[2])'/>
      <d:creator>Ralph Swick</d:creator>
      <a:created>1999-10-14T12:10Z</a:created>
      <d:date>1999-10-14T12:10Z</d:date>
      <a:body
       r:resource="http://example.org/CGI/annot?body=/2000/05/08-18:04:55" />
   </r:Description>

Figure 10: A sample answer to the query in Figure 9.

Currently, Amaya can only send the annotation server couple of different types of queries, such as the one presented in Figure 11, asking for all the annotations related to a page at a given URI. In addition, as a first step to support a more general query mechanism users capable of doing so can write Algae queries in a text box in Amaya. In the future, we plan to extend the query language following closely the work on XML Query working group and try to develop better user interfaces for the queries.

GET /CGI/annot?w3c_annotates=http://example.com/some/page.html
Host: example.org

Figure 11: The client query to the server that resolves to the query in Figure 9.

Notes

[1] The use of HTTP PUT to modify annotations is the protocol as designed. For historical reasons, the W3C public Annotea service also implements modification using POST <serviceUri>?replace_source=<annotURI>. The body of the POST is identical to the body of the PUT as shown. For example, the request to modify the annotation shown in this section could be sent to annotea.example.org as: POST /annot?replace_source=http://www.example.org/Annotation/3ACF6D754.

References

[Crawford90] J. Crawford. Access-Limited Logic: A Language for Knowledge Representation. UT Artificial Intelligence TR AI90-141, Department of Computer Sciences, University of Texas at Austin, Austin, Texas., Oct. 1990.


Ralph Swick <swick>
Jose Kahan <kahan>
Eric Prud'hommeaux <eric>

$Revision: 1.14 $ of $Date: 2001/05/14 10:36:33 $ by $Author: kahan $