This specification refines the semantics and interaction patterns of [[LDP]] in order to better serve the specific needs of those interested in implementing repositories for durable access to digital data. Additionally, this specification contains:

A conforming Fedora server is a conforming [[!LDP]] 1.0 server except where described in this document that also follows the rules defined by Fedora in , , , , and .

Terminology

Terminology is based on W3C's Linked Data Platform 1.0 [[LDP]] and Memento [[RFC7089]].

LDPR:
A Linked Data Platform Resource as defined in [LDP]. This may be an LDP RDF Source (LDP-RS) or an LDP Non-RDF Source (LDP-NR).
LDP-RS:
An LDPR whose state is fully represented in RDF as defined in [LDP].
LDP-NR:
An LDPR whose state is not represented in RDF as defined in [LDP].
LDPRv:
An LDPR that is simultaneously a Memento URI-R.
LDPRm:
An LDPR that is simultaneously a Memento URI-M.
LDPC:
A collection of linked documents or information resources as defined in [LDP].
LDPCv:
A version container: an LDPC that is simultaneously a Memento TimeMap.
LDP-contained:
The relationship binding an LDPC to LDPRs whose lifecycle it controls and is aware of as defined in [LDP].
URI-R:
A type of versioned resource defined in [Memento].
URI-M:
A type of resource that is defined in [Memento] as representing a version of a given URI-R.
TimeGate:
A type of resource defined in [Memento] providing Accept-Datetime-varied negotiation of versions of an URI-R.
TimeMap:
A type of resource defined in [Memento] that contains a machine-readable listing of URI-Ms associated to a given URI-R.

Resource Management

General

If a Link: rel="type" header specifies an LDP-NR interaction model (ldp:NonRDFSource), then the server SHOULD handle subsequent requests to the newly created resource as if it is a LDP-NR. ([[!LDP]] 5.2.3.4 extension)

LDP Containers

Implementations MUST support the creation and management of [[!LDP]] Containers. LDP Direct Containers MUST NOT permit ldp:contains as their membership-predicate and requests that would do so MUST fail with 409 Conflict. ([[!LDP]] 5.4.1.4 expansion)

HTTP PATCH

Any LDP-RS MUST support PATCH ([[!LDP]] 4.2.7 MAY becomes MUST). [[!sparql11-update]] MUST be an accepted content-type for PATCH. Other content-types (e.g. [[ldpatch]]) MAY be available. If an otherwise valid HTTP PATCH request is received that attempts to add statements to a resource that a server disallows (not ignores per [[!LDP]] 4.2.4.1), the server MUST fail the request by responding with a 4xx range status code (e.g. 409 Conflict). The server MUST provide a corresponding response body containing information about which statements could not be persisted. ([[!LDP]] 4.2.4.4 SHOULD becomes MUST). In that response the restrictions causing such a request to fail MUST be described in a resource indicated by a Link: rel="http://www.w3.org/ns/ldp#constrainedBy" response header per [[!LDP]] 4.2.1.6. A successful PATCH request MUST respond with a 2xx status code; the specific code in the 2xx range MAY vary according to the response body or request state.

Interaction models

The server MUST disallow a PATCH request that would change the LDP interaction model of a resource to a type that is not a subtype of the current resource type. That request MUST be rejected with a 409 Conflict response.

HTTP POST

Any LDPC MUST support POST ([[!LDP]] 4.2.3 / 5.2.3). The default interaction model that will be assigned when there is no explicit Link header in the request MUST be recorded in the constraints document referenced in the Link: rel="http://www.w3.org/ns/ldp#constrainedBy" header ([[!LDP]] 4.2.1.6 clarification). Any LDPC MUST support creation of LDP-NRs on POST ([[!LDP]] 5.2.3.3 MAY becomes MUST). On creation of an LDP-NR an implementation MUST create an associated LDP-RS describing that LDP-NR ([[!LDP]] 5.2.3.12 MAY becomes MUST).

LDP-NRs

A HTTP POST request that would create a LDP-NR and includes a Digest header (as described in [[!RFC3230]]) for which the instance-digest in that header does not match that of the new LDP-NR MUST be rejected with a 409 Conflict response.

A HTTP POST request that includes an unsupported Digest type (as described in [[!RFC3230]]), SHOULD be rejected with a 400 Bad Request response.

Implementations SHOULD support Content-Type: message/external-body extensions for request bodies for HTTP POST that would create LDP-NRs. This content-type requires a complete Content-Type header that includes the location of the external body, e.g Content-Type: message/external-body; access-type=URL; URL=\"http://www.example.com/file\", as defined in [[!RFC2017]].

HTTP PUT

When accepting a PUT request against an extant resource, an HTTP Link: rel="type" header MAY be included. If that type is a value in the LDP namespace and is not either a current type of the resource or a subtype of a current type of the resource, the request MUST be rejected with a 409 Conflict response. If the type in the Link header is a subtype of a current type of the resource, and has an interaction model assigned to it by [[!LDP]], then the resource MUST be assigned the new type and the interaction model of the resource MUST be changed to the interaction model assigned to the new type by [[!LDP]].

LDP-NRs

Any LDP-NR MUST support PUT to replace the binary content of that resource.

A HTTP PUT request that includes a Digest header (as described in [[!RFC3230]]) for which any instance-digest in that header does not match the instance it describes, MUST be rejected with a 409 Conflict response.

A HTTP PUT request that includes an unsupported Digest type (as described in [[!RFC3230]]), SHOULD be rejected with a 400 Bad Request response.

Implementations MUST support Content-Type: message/external-body extensions for request bodies for HTTP PUT to LDP-NRs. This content-type requires a complete Content-Type header that includes the location of the external body, e.g Content-Type: message/external-body; access-type=URL; URL=\"http://www.example.com/file\", as defined in [[!RFC2017]].

LDP-RSs

Any LDP-RS MUST support PUT to update statements that are not server-managed triples (as defined in [[!LDP]] 2). [[!LDP]] 4.2.4.1 and 4.2.4.3 remain in effect. If an otherwise valid HTTP PUT request is received that attempts to add statements to a resource that a server disallows (not ignores per [[!LDP]] 4.2.4.1), the server MUST fail the request by responding with a 4xx range status code (e.g. 409 Conflict). The server MUST provide a corresponding response body containing information about which statements could not be persisted. ([[!LDP]] 4.2.4.4 SHOULD becomes MUST). In that response the restrictions causing such a request to fail MUST be described in a resource indicated by a Link: rel="http://www.w3.org/ns/ldp#constrainedBy" response header per [[!LDP]] 4.2.1.6.

Creating resources with HTTP PUT

An implementation MUST accept HTTP PUT to create resources.([[!LDP]] 4.2.4.6 MAY becomes MUST). The default interaction model that will be assigned when there is no explicit Link: rel="type" header in the request MUST be recorded in the constraints document referenced in the Link: rel="http://www.w3.org/ns/ldp#constrainedBy" header ([[!LDP]] 4.2.1.6 clarification).

HTTP GET

When the request is to the LDP-RS created to describe a LDP-NR, the response MUST include a Link: rel="describes" header referencing the LDP-NR in question, as defined in [[!RFC6892]].

Additional values for the Prefer header

In addition to the requirements of [[!LDP]], an implementation MAY support either or both of the following additional values for the Prefer header when making GET requests on LDPC resources:

  • http://www.w3.org/ns/oa#PreferContainedDescriptions: Requires a server to include representations of any contained resources in the response, as defined in [[!annotation-vocab]].
  • http://fedora.info/definitions/repository#PreferInboundReferences: Requires a server to include triples from any LDP-RS housed in that server that feature the requested resource as RDF-object.

LDP-NRs

GET requests to any LDP-NR MUST correctly respond to the Want-Digest header defined in [[!RFC3230]] unless the Content-Type of the LDP-NR is a message/external-body extension.

GET requests to a LDP-NR with Content-Type: message/external-body, MUST result in an HTTP 3xx redirect message redirecting to the external URL.

Expect: 202-digest

GET requests to a LDP-NR SHOULD respond to Expect request headers with a parameterized 202-digest expectation. Implementations MAY support unparameterized 202-digest expectations. Implementations that do not support one of these expectations MUST reject 202-digest requests for the expectation with a 417 Expectation Failed. If the LDP-NR is of Content-Type: message/external-body, the server MUST respond with a 3xx. If the digest parameter does not match the current instance digest of the resource, the request MUST be rejected with a 412 Precondition Failed. If the digest matches, the request MUST be completed with a 202 Accepted.

Expect: 202-digest and Accept:

This specification takes no position on the interaction of Expect: 202-digest and Accept: headers on the same request, or on the meaning of the 406 Unacceptable status in that context. Implementations are not required to support combinations of these headers.

Resource Versioning

Versioned Resources (LDPRv)

General

A versioned resource for this document provides a TimeGate interaction model as detailed in the Memento specification and indicated by an HTTP header Link: rel="timegate" referencing itself. It otherwise follows the relevant [[!LDP]] specification with the additional behaviors below.

HTTP GET

Request Headers for an LDPRv

Accept-Datetime, exactly as per Memento.

Response Headers

At least one Link: rel="timemap" referencing an LDPCv. It is the presence of this header that indicates that the resource is versioned.

Vary: Accept-Datetime, exactly as per Memento.

HTTP PUT

General

An LDPRv MAY support PUT. An implementation receiving a PUT request for an LDPRv MUST both correctly respond as per [[!LDP]] as well as create a new LDPRm contained in an appropriate LDPCv. The newly-created LDPRm SHOULD be the version of the LDPRv that was created by the PUT request.

Request Headers for an LDPRv

Accept-Datetime, exactly as per Memento.

Response Headers

At least one Link: rel="timemap" referencing a LDPCv. It is the presence of this header that indicates that the resource is versioned.

Vary: Accept-Datetime, exactly as per Memento.

HTTP HEAD

See:

Version Resources (LDPRm)

General

When a LDPR is created with a Link header indicating versioning, it is created as both an LDP Resource and a Memento: a LDPRm. An LDPRm MUST be invariant: While it MAY be deleted, it MUST NOT be modified once created.

HTTP DELETE

An implementation MAY support DELETE for LDPRms. If DELETE is supported, the server is responsible for all behaviors implied by the LDP-containment of the LDPRm.

HTTP GET

An implementation MUST support GET, as is the case for any LDPR. The headers for GET requests and responses on this resource MUST conform to [[!RFC7089]] (Memento). Particularly it should be noted that the relevant TimeGate for an LDPRm is the original versioned LDPRv.

HTTP HEAD

An implementation MUST support HEAD.

HTTP OPTIONS

An implementation MUST support OPTIONS. A response to an OPTIONS request MUST include Allow: GET, HEAD, OPTIONS as per [[!LDP]]. An implementation MAY include Allow: DELETE if clients can remove a version from the version history, as noted above.

HTTP PATCH

An implementation MUST NOT support PATCH for LDPRms.

HTTP POST

An implementation MUST NOT support POST for LDPRms.

HTTP PUT

An implementation MUST NOT support PUT for LDPRms.

Version Containers (LDPCv)

General

When a LDPR is created with a Link header indicating versioning, a version container (LDPCv) is created that contains Memento-identified resources (LDPRm) capturing time-varying representations of the associated LDPR. An LDPCv is both a TimeMap per [[!RFC7089]] (Memento) and an LDP Container. As a TimeMap an LDPCv MUST conform to the specification for such resources in [[!RFC7089]]. An implementation MUST indicate TimeMap in the same way it indicates the Container interaction model of the resource via HTTP headers. An LDPCv MUST respond to GET Accept: application/link-format as indicated in [[!RFC7089]] section 5 and specified in [[!RFC6690]] section 7.3.

An implementation MUST NOT allow the creation of an LDPCv that is LDP-contained by its associated LDPRv.

Non-normative: The application/link-format representation of a LDPCv is not required to include all statements in the LDPCv graph, only those required by TimeMap behaviors.

HTTP DELETE

An implementation MAY support DELETE. An implementation that does support DELETE SHOULD do so by both removing the LDPCv and removing the versioning interaction model from the original LDPRv.

HTTP OPTIONS

An implementation MUST Allow: GET, HEAD, OPTIONS as per [[!LDP]]. An implementation MAY Allow: DELETE if the versioning behavior is removable by deleting the LDPCv. See for requirements on DELETE if supported.

An implementation MAY Allow: PATCH if the LDPCv has mutable properties. See for requirements on PATCH if supported.

An implementation MAY Allow: POST if versions can be explicitly minted by a client. See for requirements on POST if supported.

HTTP PATCH

An implementation MAY Allow: PATCH, but if so, it MUST NOT permit clients to modify containment triples.

HTTP POST

If a LDPCv supports POST, POST SHOULD be understood to create a new LDPRm contained by the LDPCv, reflecting the state of the LDPRv at the time of the POST. If supported, but the representation at the time of version creation can only be that which is current for the LDPRv, the Accept-Post header of any response from the LDPCv SHOULD indicate that no request body is accepted via the form Accept-Post: */*; p=0.0, and that implementation SHOULD respond to any body-containing POST to that LDPCv with a 415 response and a link to an appropriate constraints document (see LDP 4.2.1.6). As per [[!LDP]], any resource created via POST, in this case a LDPRm) SHOULD be advertised in the response's Location header.

If a LDPCv does accept POST with a request body, it SHOULD respect a Memento-Datetime request header for the created LDPRm. Absent this header, it MUST use the current time.

Non-normative note: If an LDPCv does not Allow: POST, the constraints document indicated in Link: rel="http://www.w3.org/ns/ldp#constrainedBy" for that LDPCv should describe the versioning mechanism (e.g. by PUT or PATCH to the LDPRv described by that LDPCv). Disallowing POST suggests that the [[!LDP]] server will manage all LDPRm creation; see here.

Vary

When a POST to an LDPCv or PUT or PATCH to an LDPRv creates a new LDPRm, the response indicates that using a Vary header as appropriate. When a LDPCv supports POST, and allows clients to specify a datetime for created URI-Ms, Vary-Post/Vary-Put: Memento-Datetime.

Implementation Patterns

Introduction

This is a non-normative section describing the way the normative specification might be applied to implement discoverable versioning patterns. If an implementation of a LDPCv does not support POST to mint versions, that must be advertised via OPTIONS as described above. The implementation may automatically mint versions instead, but that is outside the requirements of this specification. This document specifies normatively only how LDPCvs and LDPRms can be discovered, and how they should act.

LDPRm Creation Patterns

Server-Managed Version Creation

Upon PUT or PATCH to the LDPRv, a new LDPRm is created in an appropriate LDPCv. This LDPRm is the version of the original LDPRv that was just created.

Client-Managed Version Creation

An LDPRm for a particular LDPRv is created on POST to any LDPCv associated with that LDPRv. The new LDPRm is contained in the LDPCv to which the POST was made and features in that LDPCv-as-aTimeMap . This pattern is more open to manipulation and could be useful for migration from other systems into Fedora implementations. Responses from requests to the LDPRv include a Link: rel="timemap" to the same LDPCv as per [[!RFC7089]] (Memento).

Binary Resource Fixity

What is fixity?

For the purposes of the following specification, a fixity result is an extract or summary of some LDP-NR made according to some explicit procedure. Fixity results are taken for the purpose of comparing different fixity results for the same resource over time, to ensure a continuity of that resource's identity according to the particular procedure used. Examples might include:

This specification describes two fixity verification mechanisms: firstly, as part of content transmission, to guard against faults in transmission, and secondly, by comparison to a known or proffered digest value, to monitor for faults in persistence.

Transmission Fixity

Transmission fixity is verified by application of the Digest header defined in [[RFC3230]] to POST and PUT requests for LDP-NR.

Persistence Fixity

Extension of Expect header

In the minimal case, a client that has an original digest value can verify persistence fixity by downloading the LDP-NR and calculating the checksum. To avoid the necessity of transferring a potentially large binary, this specification describes a new expectation token for the Expect header described in [[RFC7231]]: 202-digest, and a digest-link parameter.

Expect: 202-digest

The 202-digest expectation indicates that the client is requesting that the server verify an instance digest for the resource at the request IRI.


            Expect                  =  "Expect" ":" 1#digest-expectation
            digest-expectation      = "202-digest" [(digest-param|digest-link-param)]
            digest-param            = ";" #(instance-digest)
            digest-link-param       = ";" "digest-link" "=" IRI-reference
          

instance-digest values are of the syntax described in [[!RFC3230]] for the Digest header. IRI-reference values for the digest-link-param are described in [[!RFC3987]].

HTTP/1.1 servers that do not support the 202-digest expectation MUST reject requests with 417 Expectation Failed.

An implementing server MAY allow 202-digest without a digest-param, indicating that the compared and calculated digests are selected by the server. Such servers SHOULD compare the calculated instance digest to a stored original digest. Servers that require a client-proffered digest-param MUST reject requests without a digest with 417 Expectation Failed.

If the compared digests do not match, an implementing server MUST reject the request with 412 Precondition Failed. If the compared digests match, an implementing server MUST complete the request with 202 Accepted. A client that receives a non-202 response to a 202-digest expectation SHOULD assume it is responsible for verifying fixity by downloading the resource.

An implementing server SHOULD accompany HTTP status 417 and 412 responses with an explanatory entity.

Resource Authorization

To configure access control restrictions, implementations MUST follow the recommendations of [[!SOLIDWEBAC]].

Implementations supporting access control MUST use the [[!WEBAC]] model to configure that functionality. Any access control resource in use MUST be a LDP-RS, which SHOULD be located in the same server as the controlled resource. Implementations MUST support extended control relationships in which the access control resource for some resource has its own access control resource and so on. Implementations MUST make access control resources discoverable via the Link: rel="acl" HTTP header, as discussed here.

Inheritance

An implementation MUST respect [[!LDP]]-containment for access control, as described here.

Messaging

Introduction

This section defines when messages are emitted by a Fedora implementation, the minimal set of data contained in those messages and how those data are serialized. These messages may occur synchronously or asynchronously with the API operations that cause them to be emitted. They are typically used to support external integrations. The structure of these messages draws upon the existing [[activitystreams-core]] and [[ldn]] specifications. An implementation is free to choose from any messaging technology so long as the messages conform to what is described in the following sections.

Emitting Messages

Any operation that causes the state of a resource to durably change MUST cause a message to be emitted with a corresponding resource identifier.

A failed operation (HTTP 4xx or 5xx) MUST NOT emit any messages.

Messages MUST NOT be emitted until after any changes have been persisted to durable storage.

Repository start, stop and configuration change operations MAY cause a message to be emitted.

Any operation on an LDPR that results in a change to the containment or membership triples of a distinct other LDPR MUST also trigger an event for that other LDPR.

Any operation that causes contained resources to change MUST trigger corresponding events for those resources. For example, deleting a parent resource and thereby changing the state of its child resources MUST result in corresponding events for each of the contained child resources.

Non-normative: consumers of these messages should not expect a strict ordering of the events reported therein: the fact that a message for Event A is received before a message for Event B should not imply that Event A occurred before Event B. Implementations may choose to make further guarantees about ordering.

Message Data

Emitted events MUST contain exactly one value for each of the following elements:

A message MUST contain at least one value for the event type. Event types SHOULD be drawn from the [[!activitystreams-vocabulary]].

A message SHOULD contain at least one value for the agent operating on the resource.

A message SHOULD contain a collection of RDF types corresponding to the resource that was changed.

If the corresponding LDPR includes an ldp:inbox, the location of that inbox SHOULD be included in the message.

Messages MAY contain a timestamp marking the time the resource was added/modified/deleted.

Messages SHOULD NOT contain the entire content of repository resources.

Message Serialization

The message body serialization MUST conform to the [[!activitystreams-core]] specification.

Wherever possible, data SHOULD be expressed using the [[!activitystreams-vocabulary]].

Examples

A minimal message

{
  "@context": "https://www.w3.org/ns/activitystreams",
  "id": "urn:uuid:3c834a8f-5638-4412-aa4b-35ea80416a18",
  "type": "Create",
  "name": "Resource Creation",
  "actor": "http://example.org/agent/fedoraAdmin",
  "object": {
    "id": "http://example.org/fcrepo/rest/resource/path",
    "type": [
      "ldp:Container",
      "ldp:RDFSource"
    ]
  }
}
            

A basic event with some additional detail

{
  "@context": [
    "https://www.w3.org/ns/activitystreams",
    {
      "isPartOf": {
        "@id": "http://purl.org/dc/terms/date",
        "@type": "@id"
      }
    }
  ],
  "id": "urn:uuid:be29ae69-2134-f1b0-34be-2f91b6d1f029",
  "type": "Update",
  "name": "Resource Modification",
  "published": "2016-07-04T13:46:39Z",
  "inbox": "http://example.org/ldn/inbox/path",
  "actor": [
    {
      "id": "#actor0",
      "type": "Person",
      "name": "fedo raAdmin"
    },
    {
      "id": "#actor1",
      "type": "Service",
      "name": "APIX-core/0.1"
    }
  ],
  "object": {
    "id": "http://example.org/fcrepo/rest/resource/path",
    "updated": "2016-07-04T13:44:39Z",
    "type": [
      "ldp:Container",
      "ldp:RDFSource",
      "http://example.org/type/CustomType"
    ],
    "isPartOf": "http://example.org/fcrepo/rest/"
  }
}
            

Acknowledgments