Copyright © 2016 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 Working Draft. If you wish to make comments regarding this document, please send them to public-annotation@w3.org (subscribe, archives). All comments are welcome.
Publication as a 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 September 2015 W3C Process Document.
This section is non-normative.
Interoperability between systems has two basic aspects: the syntax and semantics of the data that is moved between the systems, and the transport mechanism for that movement. The HTTP protocol and the Web architecture provides us with a great starting point for a standardized transport layer, and can be used to move content between systems easily and effectively. Building upon these foundations allows us to make use of existing technology and patterns to ensure consistency and ease of development.
The Web Annotation Protocol describes a transport mechanism for creating, managing, and retrieving Annotations. Annotations in this specification are assumed to follow the requirements of the Web Annotation Data Model [annotation-model] and Web Annotation Vocabulary [annotation-vocab]. This specification builds upon REST principles and 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 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 pair.
For those familiar with the Web Annotation model, LDP and REST, much of the Annotation Protocol will be very obvious. The following aspects are the most important new requirements.
application/ld+json;profile="http://www.w3.org/ns/anno.jsonld"
ldp:constrainedBy
URL is http://www.w3.org/TR/annotation-protocol/
rel
type of: http://www.w3.org/ns/oa#annotationService
As well as sections marked as non-normative, all authoring guidelines, diagrams, examples, and notes in this specification are non-normative. Everything else in this specification is normative.
The key words MAY, MUST, RECOMMENDED, SHOULD, and SHOULD NOT are to be interpreted as described in [RFC2119].
The Web Annotation Protocol is defined using the following basic principles:
The Annotation Server MUST support the following HTTP methods on the Annotation's URI:
GET
(retrieve the description of the Annotation), HEAD
(retrieve the headers of the Annotation without an entity-body),OPTIONS
(enable CORS pre-flight requests [cors]).Servers MUST support the JSON-LD representation using the Web Annotation profile. These responses MUST have a Content-Type
header with the application/ld+json
media type, and it SHOULD have the Web Annotation profile URI of http://www.w3.org/ns/anno.jsonld
in the profile
parameter.
Servers SHOULD support a Turtle representation, and MAY support other formats. If more than one representation of the Annotation is available, then the server SHOULD support content negotiation. Content negotiation for different serializations is performed by including the desired media type in the HTTP Accept
header of the request, however clients cannot assume that the server will honor their preferences [rfc7231].
Servers MAY support different JSON-LD profiles. Content negotiation for different JSON-LD profiles is performed by adding a profile
parameter to the JSON-LD media type in a space separated, quoted list as part of the Accept
header.
The response from the Annotation Server 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 of http://www.w3.org/ns/oa#Annotation
MAY also be added with the same rel
type.
The response MUST have an ETag
header with an entity reference value that implements the notion of entity tags from HTTP [rfc7232].
The response MUST have an Allow
header that lists the HTTP methods available for the Annotation [rfc7231].
The response MUST have a Vary
header with Accept
in the value. [rfc7231]
GET /annotations/anno1 HTTP/1.1 Host: example.org Accept: application/ld+json; profile="http://www.w3.org/ns/anno.jsonld"
HTTP/1.1 200 OK Content-Type: application/ld+json; profile="http://www.w3.org/ns/anno.jsonld" Link: <http://www.w3.org/ns/ldp#Resource>; rel="type" ETag: "_87e52ce126126" Allow: PUT,GET,OPTIONS,HEAD,DELETE,PATCH Vary: Accept Content-Length: 243 { "@context": "http://www.w3.org/ns/anno.jsonld", "id": "http://example.org/annotations/anno1", "type": "Annotation", "created": "2015-01-31T12:03:45Z", "body": { "type": "TextualBody", "text": "I like this page!" }, "target": "http://www.example.com/index.html" }
If the Annotation Server supports the management of Annotations, including one or more of creating, updating and deleting them, then the following section's requirements apply. The Annotation Protocol is a use of the Linked Data Platform [ldp] specification, with some additional constraints derived from the Web Annotation Data Model [annotation-model].
An Annotation Server MUST provide one or more Containers within which Annotations can be managed: an Annotation Container. An Annotation Container is at the same time both a Container [ldp] (a service for managing Annotations) and a Collection [activitystreams-core] (an ordered list of Annotations). It can have descriptive and technical information associated with it to allow clients to present it to a user in order to allow her to decide if it should be used or not.
Annotation Containers SHOULD implement the LDP Basic Container specification, but implementers MAY instead implement it as one of the other types of Container, such as a Direct or Indirect Container, to fulfill business needs. Annotation Containers MAY have any URI, but MUST end in a "/"
character. The Annotations MUST be assigned URIs with an additional path component below the Container's URI.
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 Annotation Server MUST support the following HTTP methods on the Annotation Container's URI:
GET
(retrieve the description of the Container and the list of its contents, described below), HEAD
(retrieve the headers of the Container without an entity-body),OPTIONS
(enable CORS pre-flight requests [cors]).
When an HTTP GET request is issued against the Annotation Container, the server MUST return a description of the container. That description MUST be available in JSON-LD, SHOULD be available in Turtle, and MAY be available in other formats. The JSON-LD serialization of the Container's description SHOULD use both the LDP context (http://www.w3c.org/ns/ldp.jsonld
), and the Web Annotation's profile and context [annotation-model], unless the request would determine otherwise.
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.
All supported methods for interacting with the Annotation Container MUST be advertised in the Allow
header of the GET
, HEAD
and OPTIONS
responses from the container's URI . The Allow
header MAY also be included on any other responses.
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/
, and the rel
parameter value is the URI http://www.w3.org/ns/ldp#constrainedBy
.
All HTTP responses from Annotation Containers MUST include an ETag
header, that implements the notion of entity tags from HTTP [rfc7230].
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.
Responses from Annotation Containers that support the use of the POST method to create Annotations SHOULD include an Accept-Post
header on responses to GET, HEAD and OPTIONS requests. The value is a comma separated list of media-types that are acceptable for the client to send via POST [ldp].
Link: <http://www.w3.org/ns/ldp#BasicContainer>; rel="type", <http://www.w3.org/TR/annotation-protocol/>; rel="http://www.w3.org/ns/ldp#constrainedBy" ETag: "0f6b5cd8dc1f754a1738a53b1da34f6b" Vary: Accept Allow: POST, GET, OPTIONS, HEAD
Prefer
request header set to the value return=representation;include="http://www.w3.org/ns/ldp#PreferMinimalContainer"
.Prefer
request header set to the value return=representation;include="http://www.w3.org/ns/oa#PreferContainedURIs"
.Prefer
request header set to the value return=representation;include="http://www.w3.org/ns/oa#PreferContainedDescriptions"
.The Client may request the description of the Annotation Container without any included Annotations.
Collection SHOULD include links to the first and last CollectionPages.GET /annotations/ HTTP/1.1 Host: example.org Accept: application/ld+json; profile="http://www.w3.org/ns/anno.jsonld" Prefer: return=representation;include="http://www.w3.org/ns/ldp#PreferMinimalContainer"
HTTP/1.1 200 OK Content-Type: application/ld+json; profile="http://www.w3.org/ns/anno.jsonld" ETag: "_87e52ce123123" Link: <http://www.w3.org/ns/ldp#BasicContainer>; rel="type" <http://www.w3.org/TR/annotation-protocol/>; rel="http://www.w3.org/ns/ldp#constrainedBy" Allow: POST,GET,OPTIONS,HEAD Vary: Accept Content-Length: 221 { "@context": [ "http://www.w3.org/ns/anno.jsonld", "http://www.w3.org/ns/ldp.jsonld" ], "id": "http://example.org/annotations/", "type": ["BasicContainer", "AnnotationCollection"], "total": 42023, "label": "A Container for Web Annotations", "first": "http://example.org/annotations/?page=0", "last": "http://example.org/annotations/?page=42" }
If the client requests a response that would include the Annotations, either by URI or embedded in the response, then the server MUST use the paged collection model. Each page, described below, will contain an ordered list with a subset of the managed annotations, such that if every page is traversed, a client can reconstruct the complete, ordered contents of the container. The number of URIs or Annotation descriptions included on each page is at the server's discretion, and may be inconsistent between pages. The feature or features by which the annotations are sorted are not explicit in the response.
The Collection SHOULD include the total
property with the total number of annotations in the container. It MUST also have a link to the first page of its contents using first
, and SHOULD have a link to the last page of its contents using last
.
The URI of the Collection in the response should differentiate between whether the pages contain just the URIs, or the full descriptions of the Annotations. It is RECOMMENDED that this be done with a query parameter. The server MAY redirect the client to this URI and deliver the response there, otherwise it MUST include a Content-Location
header with the URI as its value. The server SHOULD include Prefer
in the Vary
response header to assist with caching.
GET /annotations/ HTTP/1.1 Host: example.org Accept: application/ld+json; profile="http://www.w3.org/ns/anno.jsonld" Prefer: return=representation;include="http://www.w3.org/ns/ldp#PreferContainedURIs"
HTTP/1.1 200 OK Content-Type: application/ld+json; profile="http://www.w3.org/ns/anno.jsonld" Content-Location: http://example.org/annotations/?uris=1 ETag: "_87e52ce123123" Link: <http://www.w3.org/ns/ldp#BasicContainer>; rel="type" <http://www.w3.org/TR/annotation-protocol/>; rel="http://www.w3.org/ns/ldp#constrainedBy" Allow: POST,GET,OPTIONS,HEAD Vary: Accept, Prefer Content-Length: 221 { "@context": [ "http://www.w3.org/ns/anno.jsonld", "http://www.w3.org/ns/ldp.jsonld" ], "id": "http://example.org/annotations/?uris=1", "type": ["BasicContainer", "AnnotationCollection"], "total": 42023, "label": "A Container for Web Annotations", "first": "http://example.org/annotations/?uris=1&page=0", "last": "http://example.org/annotations/?uris=1&page=42" }
Individual pages are instances of CollectionPage
. The page contains the Annotations, either via their URIs or full descriptions, in the items
property.
Each page MUST have a link to the container that it is part of, using the partOf
property. If it is not the first page, it MUST have a link to the previous page in the sequence, using the prev
property. If it is not the last page, it MUST have a link to the next page in the sequence, using the next
property. The response MAY include properties of the Collection in the response, including the total number of items or first and last page links.
The client SHOULD NOT send the Prefer
header when requesting the page, as it has already been taken into account when requesting the Container.
This specification does not require any particular functionality when a client makes requests other than GET, HEAD or OPTIONS to a page.
As the CollectionPage
is not a Container, it does not have the requirement to include a Link
header with a type. That the URLs can be constructed with query parameters added to the Container's URI is an implementation convenience, and does not imply the type of the resource.
GET /annotations/?uris=1&page=0 HTTP/1.1 Host: example.org Accept: application/ld+json; profile="http://www.w3.org/ns/anno.jsonld"
HTTP/1.1 200 OK Content-Type: application/ld+json; profile="http://www.w3.org/ns/anno.jsonld" Allow: GET,OPTIONS,HEAD Vary: Accept, Prefer Content-Length: 221 { "@context": "http://www.w3.org/ns/anno.jsonld", "id": "http://example.org/annotations/?uris=1&page=0", "type": "AnnotationPage", "partOf": { "id": "http://example.org/annotations/?uris=1", "total": 42023 }, "next": "http://example.org/annotations/?uris=1&page=1", "items": [ "http://example.org/annotations/anno1", "http://example.org/annotations/anno2", "http://example.org/annotations/anno3", "http://example.org/annotations/anno4", "http://example.org/annotations/anno5", "http://example.org/annotations/anno6", ... "http://example.org/annotations/anno999", ] }
As the URI for Annotation Containers MAY be any URI, and it is unlikely that every Web Server will support the functionality, it is important to be able to discover the availability of these services.
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
.
For HTML representations of 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 via a POST request of 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 Web Annotation JSON-LD profile, and servers MAY reject other contexts even if they would otherwise produce the same model. The server MAY reject content that is not an Annotation according to the Web Annotation specification.
Upon receipt of an Annotation, the server SHOULD assign HTTP URIs to all 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 MAY 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.
If the Annotation contains a canonical
link, then it MUST be maintained without change. If the Annotation has a URI in the id
property, then it SHOULD be copied to the via
property, and the URI assigned by the server at which the Annotation is available MUST be put in the id
field to replace it.
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 MUST be the Annotation as now managed by the server, including any additional URIs or data created in the process or without any information that was sent but not stored. Barring content negotiation, the response SHOULD be serialized in JSON-LD following the Annotation Data Model specification.
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 Web 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. If the container preferences described above are supported, this MUST also include Prefer
.
POST /annotations/ HTTP/1.1 Host: example.org Accept: application/ld+json; profile="http://www.w3.org/ns/anno.jsonld" Content-Type: application/ld+json; profile="http://www.w3.org/ns/anno.jsonld" Content-Length: 153 { "@context": "http://www.w3.org/ns/anno.jsonld", "type": "Annotation", "body": { "type": "TextualBody", "value": "I like this page!" }, "target": "http://www.example.com/index.html" }
HTTP/1.1 201 CREATED Link: <http://www.w3.org/ns/ldp#BasicContainer>; rel="type" <http://www.w3.org/TR/annotation-protocol/>; rel="http://www.w3.org/ns/ldp#constrainedBy" Allow: PUT,GET,OPTIONS,HEAD,DELETE,PATCH Vary: Accept Location: http://example.org/annotations/anno1 Content-Type: application/ld+json; profile="http://www.w3.org/ns/anno.jsonld" Content-Length: 243 ETag: "_87e52ce126126" { "@context": "http://www.w3.org/ns/anno.jsonld", "id": "http://example.org/annotations/anno1", "type": "Annotation", "created": "2015-01-31T12:03:45Z", "body": { "type": "TextualBody", "text": "I like this page!" }, "target": "http://www.example.com/index.html" }
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; profile="http://www.w3.org/ns/anno.jsonld" Content-Type: application/ld+json; profile="http://www.w3.org/ns/anno.jsonld" Content-Length: 153 Slug: "my_first_annotation" { "@context": "http://www.w3.org/ns/anno.jsonld", "type": "Annotation", "body": { "type": "TextualBody", "text": "I like this page!" }, "target": "http://www.example.com/index.html" }
HTTP/1.1 201 CREATED Link: <http://www.w3.org/ns/ldp#BasicContainer>; rel="type" Allow: PUT,GET,OPTIONS,HEAD,DELETE,PATCH Location: http://example.org/annotations/my_first_annotation Content-Type: application/ld+json; profile="http://www.w3.org/ns/anno.jsonld" ETag: "_87e52ce126126" Vary: Accept Content-Length: 257 { "@context": "http://www.w3.org/ns/anno.jsonld", "id": "http://example.org/annotations/my_first_annotation", "type": "Annotation", "created": "2015-01-31T12:03:45Z", "body": { "type": "TextualBody", "text": "I like this page!" }, "target": "http://www.example.com/index.html" }
Annotations can be updated by using a PUT request to replace the entire state of the Annotation. Annotation Servers SHOULD support this method. Servers MAY also support using a PATCH request 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 PUT method, where the body of the request is the intended new state of the 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 modifying the same Annotation 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; profile="http://www.w3.org/ns/anno.jsonld" Content-Type: application/ld+json; profile="http://www.w3.org/ns/anno.jsonld" Content-Length: 163 If-Match: "_87e52ce126126" { "@context": "http://www.w3.org/ns/anno.jsonld", "id": "http://example.org/annotations/anno1", "type": "Annotation", "created": "2015-02-01T10:13:40Z", "body": { "type": "TextualBody", "text": "I REALLY like this page!" }, "target": "http://www.example.com/index.html" }
HTTP/1.1 200 OK Content-Type: application/ld+json; profile="http://www.w3.org/ns/anno.jsonld" 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/anno.jsonld", "id": "http://example.org/annotations/anno1", "type": "Annotation", "created": "2015-02-01T10:13:40Z", "modified": "2015-02-02T20:43:19Z" "body": { "type": "TextualBody", "text": "I REALLY like this page!" }, "target": "http://www.example.com/index.html" }
Clients use the DELETE method to request that an Annotation be deleted. Annotation Servers SHOULD 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
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 and protocol.
The following people have been instrumental in providing thoughts, feedback, reviews, content, criticism and input in the creation of this specification: