Copyright © 2015 W3C® (MIT, ERCIM, Keio, Beihang). W3C liability, trademark and document use rules apply.
Annotations are typically used to convey information about a resource or associations between resources. Simple examples include a comment or tag on a single web page or image, or a blog post about a news article.
The Web Annotation Protocol describes the transport mechanisms for creating and managing annotations in a method that is consistent with the Web Architecture and REST best practices.
This section describes the status of this document at the time of its publication. Other documents may supersede this document. A list of current W3C publications and the latest revision of this technical report can be found in the W3C technical reports index at http://www.w3.org/TR/.
This is a work in progress. No section should be considered final, and the absence of any content does not imply that such content is out of scope, or may not appear in the future. If you feel something should be covered, please tell us!
This document was published by the Web Annotation Working Group as a First Public Working Draft. This document is intended to become a W3C Recommendation. If you wish to make comments regarding this document, please send them to public-annotation@w3.org (subscribe, archives). All comments are welcome.
Feedback on this specification can be made via annotations. All annotations are archived on the public-annotation@w3.org mailing list (archives), and on the searchable WebPlatform Notes stream; see more details on Notes.WebPlatform.org. Note: To create annotations, you must have a WebPlatform.org account; do not use your W3C credentials.
Publication as a First Public Working Draft does not imply endorsement by the W3C Membership. This is a draft document and may be updated, replaced or obsoleted by other documents at any time. It is inappropriate to cite this document as other than work in progress.
This document was produced by a group operating under the 5 February 2004 W3C Patent Policy. W3C maintains a public list of any patent disclosures made in connection with the deliverables of the group; that page also includes instructions for disclosing a patent. An individual who has actual knowledge of a patent which the individual believes contains Essential Claim(s) must disclose the information in accordance with section 6 of the W3C Patent Policy.
This document is governed by the 1 August 2014 W3C Process Document.
This section is non-normative.
The Web Annotation Protocol describes a series of transport mechanisms for creating, managing, retrieving and searching for annotations, as well as notifying systems of these events. Annotations in this specification follow the data model, vocabulary and serialization requirements of the Web Annotation Data Model.
The Web Annotation Protocol is specified in three documents, which describe the methods by which:
This specification primarily builds upon the Linked Data Platform [ldp] recommendation, and familiarity with it is recommended.
The primary aim of the Web Annotation Protocol is to provide a standard set of interactions that, when implemented, will allow annotation clients and servers to interoperate seamlessly. By being able to discover annotation protocol end-points and how to interact with them, clients can be configured either automatically or by the user to store annotations in any compatible remote system, rather than being locked in to a single client and server product pair.
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 [rfc2119].
The Web Annotation Protocol is defined using the following basic principles:
All Annotations are managed within a Container. The Container has a URI which provides the service endpoint through which Annotations may be created and from which the list of managed Annotations may be retrieved. The Annotations will be assigned URIs with an additional path component below the Container's URI.
A conforming server MUST provide one or more LDP Containers within which Annotations may be managed, an Annotation Container.
Annotation Containers SHOULD implement the LDP Basic Container specification, but implementers MAY instead implement it as a Direct or Indirect Container to fulfill business needs.
Annotation Containers MAY have any URI, but MUST end in a "/"
character.
The creation, management and structure of Annotation Containers are beyond the scope of this specification. Please see the Linked Data Platform specification [ldp] for additional information in this regard.
The server MUST support the following HTTP methods on the Annotation Container's URI:
POST
(create a new Annotation, described in 4.2.1),GET
(retrieve the description of the Container and the list of its contents, described below), OPTIONS
(enable CORS pre-flight requests).
All supported methods for interacting with the Annotation Container MUST be advertised in the Allow
header of all responses from the container.
Annotation Containers MUST return a Link
header [rfc5988] on all responses with the following components:
rel
parameter value is type
and the target IRI is the appropriate Container Type, such as http://www.w3.org/ns/ldp#BasicContainer
for Basic Containers.http://www.w3.org/TR/annotation-protocol/constraints
, and the rel
parameter value is the URI http://www.w3.org/ns/ldp#constrainedBy
. (Additional Constraint)All HTTP responses from Annotation Containers MUST include an ETag header, that implements the notion of entity tags from HTTP [rfc7230].
HTTP Responses from Annotation Containers MUST include a Vary header. The value MUST include Accept, and MAY include any other headers used to determine the representation provided in the response. (Additional Constraint)
Link: <http://www.w3.org/ns/ldp#BasicContainer>; rel="type", <http://www.w3.org/TR/annotation-protocol/constraints>; rel="http://www.w3.org/ns/ldp#constrainedBy" ETag: "0f6b5cd8dc1f754a1738a53b1da34f6b" Vary: Accept Allow: POST, GET, OPTIONS, HEAD
When an HTTP GET request is issued against the Annotation Container, the server MUST return a description of the container. That description MUST be in RDF, and available in at least JSON-LD and Turtle formats.
Clients that have a preference for JSON-LD SHOULD explicitly request it using an Accept
header on the request. If the Accept
header is absent from the request, then Annotation Servers MUST respond with the JSON-LD representation of the Annotation Container(Additional Constraint).
The description returned MUST include the URI of the container and its type. It MAY include other properties or relationships to other resources, and SHOULD include a human readable label using the rdf:label
predicate. Other properties might include a description or a link to the acceptable usage terms for the service. The list of annotations within the container MUST be included unless a preference is specified by the client, described below.
If the server supports more than one Annotation container, each such container's description SHOULD include links to all other containers using the predicate iana:alternate
. The URI for the alternate service SHOULD be absolute, and MAY be provided by another institution. (Additional Constraint)
The JSON-LD serialization of the Container's description SHOULD use the Open Annotation's context, http://www.w3.org/ns/oa
. (Additional Constraint)
For an Annotation Container that contains four Annotations, an example GET request and response with relative Annotation URIs might look like:
Request:GET /annotations/ HTTP/1.1 Host: example.org Accept: application/ld+json
HTTP/1.1 200 OK Content-Type: application/ld+json ETag: "_87e52ce123123" Link: <http://www.w3.org/ns/ldp#BasicContainer>; rel="type" <http://www.w3.org/TR/annotation-protocol/constraints>; rel="http://www.w3.org/ns/ldp#constrainedBy" Allow: POST,GET,OPTIONS,HEAD Vary: Accept Content-Length: 221 { "@context": "http://www.w3.org/ns/oa", "@id": "http://example.org/annotations/", "@type": "BasicContainer", "label": "A Container for Open Annotations", "alternate": ["http://example.org/annotations2/", "http://example.org/moreAnnotations/"], "contains": ["anno1","anno2","anno3","anno4"] }
As more and more annotations are created, the representation of the Container will continue to grow to the point where it is not manageable to either generate or retrieve the complete list of contained resources.
If the client wishes to retrieve only the description of the container, without the list of annotations that it contains, then it SHOULD issue a request with the Prefer
header set to the value return=representation; omit="http://www.w3.org/ns/ldp#PreferContainment"
. This informs the server that the client prefers that the containment triples (those of the form "container ldp:contains annotation") SHOULD be omitted, but everything else included in the returned representation.
Paging the response is also possible, using the LDP Paging specification [ldp-paging], summarized here.
The client can request a maximum number of annotations to be listed in the response to (for example) 1000 by including a Prefer
header of return=representation; max-member-count="1000"
. The integer value MUST be 1 or greater, and the omit preference described above should be used instead if no containment triples are desired. Servers MUST process this request using the method described.
When a paging preference is received, instead of returning the representation of the container, the server MUST return a response with the status code of 303
and a Location
header with the URI for the first page. If the page size requested is larger than the number of contained Annotations, then the server MUST still perform this redirect and there will only be one page in the set.
The first page MUST include all of the descriptive properties of the Annotation Container, and the first n references to the contained Annotations. Subsequent pages MUST include only the appropriate n references to the next set of Annotations.
Traversal between pages is performed by following references obtained from Link
headers in the responses:
rel
parameter with the value "next"
, apart from the final page which does not have a next link
rel
parameter with the value "prev"
rel
parameter with the value "first"
rel
parameter with the value "last"
Each page MUST include a Link
header entry with the rel
parameter value of "canonical"
, and the target IRI of the Annotations container being paged through. It MUST also include a etag
parameter with the value being the current ETag of the container. This allows clients to determine when the container being paged has changed between requests, and hence the pages being served may be out of sync.
Each page MUST include a Link
header entry with the rel
parameter value of "type"
, and the target IRI of "http://www.w3.org/ns/ldp#Page"
to let clients know that they have arrived at a page of a larger resource, not the complete representation.
If paging or the client preference for minimal container information is supported, the Annotation Container's Vary
header MUST include Prefer
in the value, along with Accept
as previously specified. Individual pages do not negotiate based on the Prefer
header, and thus do not need this to be included. (Additional Constraint)
The behavior of HTTP methods other than GET when used with a page resource are not defined by this specification.
GET /annotations/ HTTP/1.1 Host: example.org Accept: application/ld+json Prefer: return=representation; max-member-count="2"
HTTP/1.1 303 See Also Location: http://example.org/annotations/?page1 Vary: Accept, Prefer Options: POST, GET, OPTIONS, HEAD ETag: v1 Content-Length: 0
GET /annotations/?page1 HTTP/1.1 Host: example.org Accept: application/ld+json
HTTP/1.1 200 OK Content-Type: application/ld+json Link: <http://example.org/annotations/?page1>; rel="first", <http://example.org/annotations/?page2>; rel="next", <http://example.org/annotations/?page2>; rel="last", <http://example.org/annotations/>; rel="canonical"; etag="v1", <http://www.w3.org/ns/ldp#Page>; rel="type" Vary: Accept Options: GET, OPTIONS, HEAD Content-Length: 289 { "@context": "http://www.w3.org/ns/oa", "@id": "http://example.org/annotations/", "@type": "BasicContainer", "label": "A Container for Open Annotations", "alternate": ["http://example.org/annotations2/", "http://example.org/moreAnnotations/"], "contains": ["anno1","anno2"] }
GET /annotations/?page2 HTTP/1.1 Host: example.org Accept: application/ld+json
HTTP/1.1 200 OK Content-Type: application/ld+json Link: <http://example.org/annotations/?page1>; rel="first", <http://example.org/annotations/?page1>; rel="prev", <http://example.org/annotations/?page2>; rel="last", <http://example.org/annotations/>; rel="canonical"; etag="v1", <http://www.w3.org/ns/ldp#Page>; rel="type" Vary: Accept Options: GET, OPTIONS, HEAD Content-Length: 121 { "@context": "http://www.w3.org/ns/oa", "@id": "http://example.org/annotations/", "contains": ["anno3","anno4"] }
As the URI for Annotation Containers MAY be any URI, and it is unlikely that every server will support the functionality, it is important to be able to discover the availability of these services. Once any one container has been discovered, alternate
links MAY be followed to discover further services, however discoverying the first container remains a challenge.
Any resource MAY link to an Annotation Container when Annotations on the resource SHOULD be created within the referenced Container. This link is carried in an HTTP Link
header and the value of the rel
parameter MUST be http://www.w3.org/ns/oa#annotationService
. (Additional Constraint)
For HTML resources, the equivalent link
tag in the header of the document MAY also be used.
For an example image resource, a GET request and response with a link to the above Annotation Container might look like:
Request:GET /images/logo.jpg HTTP/1.1 Host: example.com
HTTP/1.1 200 OK Content-Type: image/jpeg Link: <http://example.org/annotations/>; rel="http://www.w3.org/ns/oa#annotationService" Allow: GET Content-Length: 76983 [...]
New Annotations are created by posting a JSON-LD serialization of the Annotation to an Annotation Container. The Annotation's data is sent in the body of the request. All of the known information about the Annotation SHOULD be sent, and if there are already URIs associated with the resources, they MAY be included. The serialization SHOULD use the Open Annotation JSON-LD context and profile, and servers MAY reject other contexts even if they would otherwise produce the same model.
Upon receipt of an Annotation, the server MAY assign HTTP URIs to resources and blank nodes in the Annotation, and MUST assign a URI to the Annotation resource, even if it aleady has one provided in the entity body description. The server SHOULD also add additional information to the Annotation. Possible additional information includes the agent that created it, the time of the Annotation's creation, additional types and formats.
The server MUST respond with a 201
Created response if the creation is successful, and an appropriate error code otherwise. The response MUST have a Location
header with the Annotation's new URI.
The body of the response SHOULD be the Annotation as stored by the server, including any additional URIs or triples created in the process, and, barring content negotiation, it SHOULD be serialized in JSON-LD following the serialization in the Annotation Data Model specification. (Additional Constraint)
The response MUST include a Link
header with the target IRI of http://www.w3.org/ns/ldp#Resource
and the rel
parameter value of type
to advertise that this is an RDF Source, according to the LDP specification. It MAY also include the URI http://www.w3.org/ns/oa#Annotation
with the same rel
parameter of type
to also assert that it is an Annotation following the Open Annotation specifications.
The response MUST include a Vary
header with the value that includes Accept
, as the representation is negotiable based on the client's Accept header. As above, if paging or minimal container triples preferences are supported, this MUST also include Prefer
(Additional Constraint).
If the client sends content that is not an Annotation according to the Web Annotation specification, the server MAY reject it. The server MAY discard information that is not in the Web Annotation specification included in the Annotation description, but what is stored MUST be included in the body of the response. (Additional Constraint)
POST /annotations/ HTTP/1.1 Host: example.org Accept: application/ld+json Content-Type: application/ld+json Content-Length: 153 { "@context": "http://www.w3.org/ns/oa", "@type": "oa:Annotation", "body": { "@type": "oa:EmbeddedContent", "value": I like this page!" }, "target": "http://www.example.com/index.html" }
HTTP/1.1 201 CREATED Content-Type: application/ld+json ETag: "_87e52ce126126" Location: http://example.org/annotations/anno1 Link: <http://www.w3.org/ns/ldp#Resource>; rel="type" Allow: PUT,GET,OPTIONS,HEAD,DELETE,PATCH Vary: Accept Content-Length: 243 { "@context": "http://www.w3.org/ns/oa", "@id": "http://example.org/annotations/anno1", "@type": "oa:Annotation", "annotatedAt": "2015-01-31T12:03:45Z", "body": { "@type": "oa:EmbeddedContent", "value": I like this page!" }, "target": "http://www.example.com/index.html" }
Clients may retrieve an Annotation from its advertised URI with the HTTP GET
method. Servers MUST support the JSON-LD representation using the Open Annotation profile, Turtle, and MAY support other RDF serializations, other JSON-LD profiles, and other JSON-LD contexts.
Content negotiation for different JSON-LD contexts is performed by adding a profile
parameter to the JSON-LD media type in a space separated, quoted list. The URI that defines the Open Annotation profile is http://www.w3.org/TR/annotation-model/jsonLdProfile
and other specifications may define other such profiles. (Additional Constraint)
The response MUST have a Link
header entry where the target IRI is http://www.w3.org/ns/ldp#Resource
and the rel
parameter value is type
. The Annotation type MAY also be added.
The response MUST have an ETag
header, an Allow
header, and a Vary
header, as previously described.
GET /annotations/anno1 HTTP/1.1 Host: example.org Accept: application/ld+json; profile="http://www.w3.org/TR/annotation-model/jsonLdProfile"
HTTP/1.1 200 OK Content-Type: application/ld+json ETag: "_87e52ce126126" Link: <http://www.w3.org/ns/ldp#Resource>; rel="type" Allow: PUT,GET,OPTIONS,HEAD,DELETE,PATCH Vary: Accept Content-Length: 243 { "@context": "http://www.w3.org/ns/oa", "@id": "http://example.org/annotations/anno1", "@type": "oa:Annotation", "annotatedAt": "2015-01-31T12:03:45Z", "body": { "@type": "oa:EmbeddedContent", "value": I like this page!" }, "target": "http://www.example.com/index.html" }
Annotations MAY be updated by using an HTTP PUT request to replace the entire state of the Annotation. Annotation Servers MUST support this method. Servers MAY also support the use of HTTP PATCH to update only the aspects of the Annotation that have changed, but that functionality is not specified in this document.
Replacing the Annotation with a new state MUST be done with the HTTP PUT method, where the entity-body of the request is the intended complete state of the revised Annotation. The client SHOULD use the If-Match
header with a value of the ETag it received from the server before the editing process began, to avoid collisions of multiple users editing the same document at the same time.
If successful, the server MUST return a 200 OK status with the Annotation as the body according to the content-type requested.
Servers MUST advertise the availability of updating via PUT on requests to the Annotation's URI using the Allow response header.
PUT /annotations/anno1 HTTP/1.1 Host: example.org Accept: application/ld+json Content-Type: application/ld+json Content-Length: 163 If-Match: "_87e52ce126126" { "@context": "http://www.w3.org/ns/oa", "@id": "http://example.org/annotations/anno1", "@type": "oa:Annotation", "annotatedAt": "2015-02-01T10:13:40Z", "body": { "@type": "oa:EmbeddedContent", "value": I REALLY like this page!" }, "target": "http://www.example.com/index.html" }
HTTP/1.1 200 OK Content-Type: application/ld+json ETag: "_87e52ce234234" Link: <http://www.w3.org/ns/ldp#Resource>; rel="type" Allow: PUT,GET,OPTIONS,HEAD,DELETE,PATCH Vary: Accept Content-Length: 243 { "@context": "http://www.w3.org/ns/oa", "@id": "http://example.org/annotations/anno1", "@type": "oa:Annotation", "annotatedAt": "2015-02-01T10:13:40Z", "body": { "@type": "oa:EmbeddedContent", "value": I REALLY like this page!" }, "target": "http://www.example.com/index.html" }
Clients use the HTTP DELETE method to request that an Annotation be deleted. Annotation Servers MUST support this method. Clients SHOULD send the ETag of the Annotation in the If-Match
header to ensure that it is operating against the most recent version of the Annotation.
If the DELETE request is successfully processed, then the server MUST return a 200 or 204 status response. The URIs of deleted Annotations SHOULD NOT be re-used for subsequent Annotations. The URI of the deleted Annotation MUST be removed from the Annotation Container it was created in.
DELETE /annotations/anno1 HTTP/1.1 Host: example.org If-Match: "_87e52ce126126"
HTTP/1.1 204 NO CONTENT Content-Length: 0
The URI path segment that is appended to the Container URI for a resource MAY be suggested by the Annotation Client by using the Slug
HTTP header on the request when the resource is created. The server SHOULD use this name, so long as it does not already identify an existing resource, but MAY ignore it and use an automatically assigned name.
POST /annotations/ HTTP/1.1 Host: example.org Accept: application/ld+json Content-Type: application/ld+json Content-Length: 153 Slug: "my_first_annotation" { "@context": "http://www.w3.org/ns/oa", "@type": "oa:Annotation", "body": { "@type": "oa:EmbeddedContent", "value": I like this page!" }, "target": "http://www.example.com/index.html" }
HTTP/1.1 201 CREATED Content-Type: application/ld+json Location: http://example.org/annotations/my_first_annotation ETag: "_87e52ce126126" Allow: PUT,GET,OPTIONS,HEAD,DELETE,PATCH Link: <http://www.w3.org/ns/ldp#Resource>; rel="type" Vary: Accept Content-Length: 257 { "@context": "http://www.w3.org/ns/oa", "@id": "http://example.org/annotations/my_first_annotation", "@type": "oa:Annotation", "annotatedAt": "2015-01-31T12:03:45Z", "body": { "@type": "oa:EmbeddedContent", "value": I like this page!" }, "target": "http://www.example.com/index.html" }
There are inevitably situations where errors occur in the when retrieving or managing Annotations. The use of the HTTP Status codes below provides a method for clients to understand the reason why a request has failed. No requirements are made regarding the entity-body of the response from the Annotation Server, however all HTTP header requirements from section 4 MUST be adhered to.
The Web Annotation Working Group gratefully acknowledges the contributions of the Open Annotation Community Group. The output of the Community Group was fundamental to the current data model.
Registration of Open Annotation JSON-LD Profile URI, per [json-ld] [rfc6906] [rfc7284]
Unclear whether this should be done in protocol or model (which includes serialization); likely in the next iteration of the model.