This is the first draft of LDP Primer Note of W3C LDP WG.
The term "Linked Data" [[LINKED-DATA]] refers to an approach to publishing data that puts linking at the heart of the notion of data, and uses the linking technologies provided by the Web to enable the weaving of a global distributed database. By naming real world entities - be they web resources, physical objects such as the Eiffel Tower, or even more abstract things such as relations or concepts - with http(s) URLs, whose meaning can be determined by dereferencing the document at that URL, and by using the relational framework provided by RDF, data can be published and linked in the same way web pages can. The Linked Data Protocol specifies how web applications can, using the HTTP protocol, find resources and follow links, publish new resources, edit and delete existing ones.
The Primer aims to provide introductory examples and guidance in the use of the LDP protocol, in accordance with best practices. For a systematic description of the protocol the reader should consult the normative LDP reference [[LDP]]. For an overview of the use cases for LDP and the elicited requirements that guided its design, the reader should consult the LDP Use Cases and Requirements [[LDP-UCR]] and for best practises and guidelines, the reader should consult the LDP LDP Best Practices and Guidelines document [[LDP-BP]].
Conventions Used in This DocumentThe examples in this guide are given as a serialization of RDF graphs using the Turtle [[TURTLE]] and JSON-LD [[JSON-LD]] syntaxes of RDF.
Commonly used namespace prefixes omitted from the Turtle serialisations:
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> . @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> . @prefix owl: <http://www.w3.org/2002/07/owl#> . @prefix ldp: <http://www.w3.org/ns/ldp#> . @prefix xsd: <http://www.w3.org/2001/XMLSchema#> . @prefix dcterms: <http://purl.org/dc/terms/> . @prefix foaf: <http://xmlns.com/foaf/0.1/> . @prefix wdrs: <http://www.w3.org/2007/05/powder-s#> . @prefix bt: <http://example.org/vocab/bugtracker#> .
The JSON-LD examples refer to the following (external) context document:
{ "@context": { "rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#", "rdfs": "http://www.w3.org/2000/01/rdf-schema#", "owl": "http://www.w3.org/2002/07/owl#", "ldp": "http://www.w3.org/ns/ldp#", "xsd": "http://www.w3.org/2001/XMLSchema#", "dcterms": "http://purl.org/dc/terms/", "foaf": "http://xmlns.com/foaf/0.1/", "wdrs": "http://www.w3.org/2007/05/powder-s#", "bt": "http://example.org/vocab/bugtracker#" } }
A server hosting Linked Data Platform Resources (LDPRs) may manage two kinds of LDPRs: those resources whose state is represented using RDF called LDP RDF Sources (LDP-RS) and those using other formats called LDP Non-RDF Source (LDP-NR) such as html files, images, other binary files, etc. Resources respond to retrieval operations using HTTP GET. A description conveyed in the response document will describe one or more entities: a Person, a Status, a Product, an Order, a Bug, a Concept, a Relation, etc. by linking it to other entities or literals. These descriptions can lead an agent to discover and process other information resources [[WEBARCH]], describing yet further entities. Those entities served by an LDP Server - a.k.a LDPRs - can themselves be described in this way, so as to enable a client to understand what consequences interacting with them entails. The description of LDPRs and their relations to entities specify what might be termed the API.
The LDP protocols covers read and write interactions with Resources. The server reveals these read/write abilities of LDP resources by describing the LDPR with sets of relations where the subject is the resource named using a URL - often a relative URL - and the relations describe various properties of the resource, such as its type, its capabilities, ... These descriptions are returned in representations of the resource on making requests on them using the HTTP GET method. The writable aspects cover creation of new resources (using the POST HTTP verbs), updates (using PUT or PATCH), and deletion (using DELETE ). Central to LDP is the Container (LDPC), which is able to respond to requests to create new resources, which it is then said to contain. Creating a resource can have additional consequences in addition to the created LDPR, such as the creation of new relation to objects described in other RDF Source's ( LDP-RS ). An LDPC can be asked at any time to list all of its contained resources. This allows for many types of applications: Document Stores containing Documents, Bug Trackers containing Bug reports, Photo Albums containing Photos, a Networth of a person containing Assets and Liabilities documents.
The simplest container is the Basic Container (LDP-BC). It allows the creation of new LDPRs, including new Containers, and a GET request on that resource lists its contained LDPRs. This can be used in a generic storage service to manage a containment hierarchy of arbitrary information resources.
Such servers do not impose any restriction on LDPRs and generally act as storage systems without any domain specific application logic and vocabularies. A client posting to such a container is not bound to any further consequences other than those that publishing that document may bind him to. Our first scenario illustrates the use Basic Containers with a document storage system.
Creating a resource in a Direct Container has as additional consequence the creation of an extra domain specific relation betwen the created resource and some entity described in a document controlled by the server. The additional assertion is called the membership triple. The relation constituing a membership triple, known as the membership predicate, can set a constraint on the types of documents posted to a container. For example the range of the foaf:depiction relation being an Image, a Direct Container with such a membership property would be expected to only allow images to be posted to such a container.
The o:hasDoc relation is not defined and it is not clear what it adds in addition to ldp:contains. A distinction without a distinction is more confusing than not.
Direct Containers can also use domain specific vocabulary and link from a resource other than the Container resource to the new resource.
Suggest replacing o:hasphoto with foaf:depiction since that relation is well known, and whose ontology can be looked up. Also make the graph inside the document more meaningful: When an object that is not a document is being described show a document with a node ( a small circle ) inside the document to which external resources can point. So in the case of a person a node inside a document representing a person, perhaps with a relative URI <#me> would make this clearer.
Different facets of a Resource can be managed using multiple Containers.
A bug is different from a bug report: a Bug can be the same as another bug reported by someone else, even if the bug reports are different, being created by different people at different times, with different histories. Distinguish in the diagram the bug from the bug report.
Existing applications with their own data model and business logic can expose their data using the LDP specification. These systems impose restrictions on LDPRs since the LDP interaction should be compliant with the underlying business logic and data model. The bug tracker example presented in the latter part of the primer is an example of an application specific LDP server.
Formal definitions of two terms LDPR and LDPC and other concepts introduced by LDP can be found in the 'Terminology' section of the Linked Data Platform 1.0 specification [[LDP]]
The following provide a set of examples to show the Linked Data Platform interactions. Note, this is a primer and should not be considered as a canonical example of ideal LDP modeling.
This section provides a set of examples of using an online document store application. These examples will demonstrate the behaviour of both types of LDPRs and LDP Basic Containers. Registration with the online document store application by a user results in some data storage space (a root Basic Container) where web resources that are supported by Linked Data Platform can be stored. Using this root Basic Container a user can create new documents and also child containers to further organize her documents stored in this application.
APIs of web applications are commonly documented by listing valid operations which can operate on URLs, where the URLs are described as templates. A description of a LDP based document store is contained in the following table. We note with emphasis that it is important for servers to use links as the main mechanism to reveal the location of resources. If it would be necessary to encode such templates into client applications, this would be a strong indicator that the design breaches a number of good design principles.
Path | Method | Description |
---|---|---|
/{username}/ | GET | Lists all the documents in the root container. |
POST | Create a new document under the root container. | |
PUT | Update the description and/or list of files of the root container. | |
PATCH | Update the description and/or list of files of the root container. | |
DELETE | Not allowed. | |
/{username}/{{document}/}*
|
GET | Retrive the document. |
POST | Discovered from the resource affordances. | |
PUT | Update the document. | |
PATCH | Partial update to the document if PATCH is supported. | |
DELETE | Delete the project description and associated bug reports. | |
/*/*
|
OPTIONS | Discover the allowed operations over a resource |
HEAD | Only retrieve metainformation about a resource |
In this example, we will see how Alice, a user of this system, does read / write management of documents using the LDP protocol. A typical interaction with the system would start with Alice registering as a user. It is likely that registration would be a LDP based interaction, but this aspect is out of scope of this example. A consequence of the registration is allocation of space for the storage of documents, and communication of this URL to the user, e.g. a basic container at http://data.example.org/alice/. This section describes a typical flow of interactions where Alice firsts reads the root document and discovers its affordances. This is followed by subsequent examples of creation, update and delete, and finishes with how the client is able to create nested structure from the containers.
First Alice looks up her storage by retrieving the LDP Basic Container assigned to her to hold her documents. Alice's LDP client does this by sending a GET request to the Resource, <http://data.example.org/alice/>.
As her document storage was just created, it is an empty container.
As shown in the example, in addition to the RDF representation of the Basic Container using the requested media type the server provides an E-tag of the resource representation and Link headers advertising that the requested resource is indeed an LDP Basic Container and it will support the LDP interaction model.
The Linked Data Platform 1.0 specification [[LDP]] says that all LDP servers MUST support Turtle media type for LDP-RS resources and SHOULD support JSON-LD media type.
Now, Alice wants to know what she can do in her document space. She can use the OPTIONS operation to learn of the permitted operations LDP-BC that she retrieved in the previous example.
OPTIONS /alice/ HTTP/1.1 Host: example.org
HTTP/1.1 200 OK Allow: OPTIONS,HEAD,GET,POST,PUT,PATCH Accept-Post: text/turtle, application/ld+json, image/bmp, image/jpeg Accept-Patch: example/patch Link: <http://www.w3.org/ns/ldp#BasicContainer>; rel='type' Content-Length: 0
Since GET on a container returns Allow this section must be rewritten with that in mind. Note, that it is also possible for a GET to return the Accept-Post headers which would reduce the need for OPTIONS.
According to the response, HTTP operations {OPTIONS,HEAD, GET,POST,PUT,PATCH} are allowed on her root container. In addition to the allowed operations, Accept-Post and Accept-Patch provides which media types are supported by the respective operations. The rel="type" Link header advertises that this resource supports LDP protocol and it is an LDP Basic Container.
In this case, the response tells Alice's LDP client that this is an LDP-Basic Container and the container allows her to POST things of both RDF types (text/turtle, application/ld+json) and images (image/bmp and image/jpeg).
Alice can upload a social profile document to her store, by POSTing her FOAF personal profile document to her LDP-BC at the root of her document store. Note, the Slug header offers the server a hint about URL of the resource to be created.
HTTP/1.1 201 Created Location: /alice/foaf Link: <http://www.w3.org/ns/ldp#Resource>; rel='type' Content-Length: 0
The response to the create request provides a Link to the newly created resource using the Location header. In this case, the server has honored the hint provided by the Slug header and created the new resource in the URL http://data.example.org
Knowing the URL of the newly created resource, Alice can check the container again to confirm that the container correctly contains the newly created resource.
Many examples below are missing the @prefix and the Content-Length
GET /alice/ HTTP/1.1 Host: example.org Accept: text/turtle
The ldp:contains containment triple discloses the newly created resource in the response.
Next, Alice wants to upload a photo of her to the document storage. She can create an image by POSTing it in the same way she created the RDF document.
POST /alice/ HTTP/1.1 Host: data.example.org Slug: avatar Link: <http://www.w3.org/ns/ldp#Resource>; rel="type" Content-Type: image/png Content- Length: nnn ### binary data ###
HTTP/1.1 201 Created Location: /alice/avatar Link: <http://www.w3.org/ns/ldp#Resource>; rel="type" Link: <http://data.example.org/alice/avatar/meta>; rel="describedby" Content-Length: 0
The outcome of creating a non-RDF is similar to creating a RDF resource. If successful, the server will return a 201 success code with a Location header that points to the created resource. Furthermore, in the case of binary resources the server may create an additional file to maintain the metadata about the binary file. In the above example, the server creates a new LDP-RS to maintain metadata about the binary resource such as creation date, owner, etc. and this metadata resource is advised using a Link header with the relation "describedby".
Similar to creating a RDF resource (LDP-RS), a containment triple will be added to the container when a non-RDF (LDP-NR) is created. Thus, the representation of the LDP container after creating the image looks like the following.
After creating the image as shown in the previous example, Alice now wants to update her FOAF profile with a link to the image. After retrieving her FOAF profile using a HTTP GET operation, she uses HTTP PUT to update the document by amending the RDF with a link to her photo.
In this example, Alice's LDP client send the E-tag of the resource representation that it retrieved previously to prevent any lost update problems.
HTTP/1.1 204 No Content Link: <http://www.w3.org/ns/ldp#Resource>; rel="type" ETag: W/"123454322"
If the operation is successful, the document will be updated with new information.
Alice can also use PATCH operation to update the resource.
Add an example with PATCH when a PATCH format is settled on.
If Alice decides to delete the image, she can do that with a delete operation.
DELETE /alice/avatar HTTP/1.1 Host: data.example.org If-Match: W/"123454322"
HTTP/1.1 204 No Content Link: <http://www.w3.org/ns/ldp#Resource>; rel="type" ETag: W/"123454322"
Does a delete need to show the type of the deleted resource? Or the etag?
As well as deleting the resource, the server removes the containment triple from the container. So a GET request on the container will return a graph isomorphic to the one described in the following representation:
For any subsequent request on the deleted resource, the server will respond with the appropriate HTTP response code.
GET /alice/avatar HTTP/1.1 Host: example.org Accept: image/png
HTTP/1.1 410 Gone
In order for the client to introduce hierachy to the management of documents, the document store allows creation of documents which are containers. That enables Alice to create a container hierarchy to organise her documents. This can be done by POSTing (a child) container representation to a (parent) container. This enables Alice to create a child container which she intends to use for image storage.
To create a new container for managing photos, Alice POSTs a representation of a container (LDP-BC) to the root container. Alice express her intention that the newly created resource should be an LDP Basic Container by including a Link header in the request with the relationship 'type'.
If the create is successful, the server responds with location of the newly created container for the photos.
HTTP/1.1 201 Created Location: /alice/photos/ Content-Length: 0
After creation of this new container, the parent container will look like
and the photo container will look like the following.
The previous section provided practical examples of basic LDP interactions using LDP Basic Containers. One of the limitations of LDP Basic Containers is that a fixed LDP vocabulary is used to assert the relations between a container and its contained resources. However, some scenarios require domain specific vocabulary to be used to list the members of a container. For example, an application which already used Linked Data and its own vocabulary may like to continue using the same vocabulary when migrating to LDP protocol. LDP Direct containers introduce the concept of membership triples allowing the flexibility to define the form of the membership. One of these flexibility points is the ability to select the predicate of the membership triple which can be from the the domain-specific vocabulary. This is done using the ldp:hasMemberRelation or ldp:isMemberOfRelation predicate of the Direct Containers.
In addition, in some scenarios it is necessary to add relationships between the newly created resource and some other resource (which is not necessarily the container or a document / information resource). This allows to define relationship between any other information resource or non-information resource (real world thing) by defining the membership constant subject or the object URI of the membership triples using ldp:membershipResource predicate of the Direct Container. The usage of the ldp:hasMemberRelation predicate as well as the ldp:membershipResource will be explained in the following examples.
Explain why this can't be done by PATCHing the other resource when needed.
For more information on information resources (documents) vs real world entities (things) separation please refer to Web Arch (Section 2.2. URI/Resource Relationships) , , Cool URIs (Section 3. URIs for Real-World Objects), URLs in Data (Section 3. Landing Pages and Records).
The examples in this section will revolve around a very simple Bug Tracker application. Bug Tracker application records the bugs of several products allowing reporting, updating and deleting bugs and products. In contrast to the online document store example, the bug tracker wants to use a simple domain vocabulary, e.g. has_bug, to express membership relationships in the containers. LDP provides the additional interaction capability in the protocol to add the domain specific triples based on the properties defined in the LDP Direct Container.
A RESTful API for a simple Bug Tracker system might be described as follows.
Path | Method | Description |
---|---|---|
/tracker/{product-id}/
|
GET | Lists the bug reports associated with a product. |
POST | Create a new bug report associated with a product. | |
PUT | Update the project description. | |
PATCH | Not supported. | |
DELETE | Delete the project description and associated bug reports. | |
/tracker/{product-id}/{bug-id}
|
GET | Gets the bug report. |
POST | Not supported. | |
PUT | Update the bug report. | |
PATCH | Not supported. | |
DELETE | Delete the bug report. | |
/*/*
|
OPTIONS | Discover the allowed operations over a resource |
HEAD | Only retrieve meta information about a resource |
In the examples in this section, we will only focus on the container representation, creation and deletion of resources because that is where the Basic Containers, Direct Containers, and Indirect Containers differ. Other operations such as updating a resource will be similar to what was illustrated in the previous example.
Continuing from the previous example, we can report a Bug against "LDP Demo" product by creating a Bug report (an LDPR representing the bug) under the "LDP Demo" product description LDPC by posting RDF representation of the Bug report to the LDPC associated with the product description.
If the creation is successful, the server responds with location of the newly created resource.
HTTP/1.1 201 Created Location: /tracker/ldp-demo/67 Content-Length: 0
If the creation fails, the server will respond with an appropriate status code depending on the error. If successful, the LDP Demo product description LDPC will have the following representation after the creation of new resource.
As you can see two new triples are added to the container. That is (</tracker/ldp-demo/>, <ldp:contains>, </tracker/ldp-demo/bug67>) and (</tracker/ldp-demo/#it>, <bt:hasbug>, </tracker/ldp-demo/bug67>). The former is added in any type of container and the latter is defined by the direct container properties.
And the created Bug resource will have the following representation. Note that server has added a server managed property, creation date (dcterms:created), and a default value for the state (bt:isInState) to the Bug in addition to what was being POSTed.
DELETE /tracker/ldp-demo/bug3 HTTP/1.1 Host: example.org If-Match: W/"123454322"
If the delete is successful, the server will respond with a success status code.
HTTP/1.1 204 No Content ETag: W/"123454322"
After the deletion, the representation of the container will look like the following
As seen from the LDP Direct Container representation above both containment triple (</tracker/ldp-demo/>, ldp:contains, </tracker/ldp-demo/bug3>) and the membership triple (</tracker/ldp-demo/#it>, bt:hasBug, </tracker/ldp-demo/bug3>) are removed from the container representation.
In this example, we will use the same scenario as in the previous example but using an LDP Indirect Container to show the differences between LDP Direct Containers and Indirect Containers and when to use LDP Indirect Containers. Though LDP Direct Containers provide the flexibility to define the constant membership URI (the subject of the membership triple when using ldp:hasMemberRelation or the object of the membership triple when using ldp:isMemberOfRelation) and the membership predicate, the member derived URI or the URI of the member is always set to the newly created document URL. LDP Indirect containers provide more flexibility by allowing the member URI to be any resource i.e. it could be either a non-information resource or a document other than the newly created resource. This done by defining the predicate to look for in the representation of the resource to be created by setting the ldp:insertedContentRelation predicate of the LDP Indirect Container. How this done will be explained in the following examples.
Continuing from the previous example, we can report a Bug Report against 'LDP demo' product by creating a Bug Report LDPR under the 'LDP Demo' product description LDPC.
The client POSTs a representation of a Bug to the Bug Tracker LDPC.
One thing to note is that the representation of the resource to be created contain a triple (< >, foaf:primaryTopic , <#it>). If the create is successful, the server responds with location of the newly created resource.
HTTP/1.1 201 Created Location: /tracker/ldp-demo/67 Content-Length: 0
If the creation fails, the server will respond with an appropriate status code depending on the error. After the resource is creation, the Product A LDPC will have the following representation.
As you can see two new triples are added to the container. That is (</app/product1>, <ldp:contains>, </tracker/ldp-demo/bug67>) and (</tracker/ldp-demo/#it>, <bt:hasbug>, </tracker/ldp-demo/bug67#it>).
It is not the focus of the Linked Data Platform WG to provide security mechanisms for read/write Linked Data applications. Though most of the security mechanisms that are applicable to general web applications are equally applicable to Linked Data applications, there is still some space to build security mechanisms specific to Linked Data applications by leverage the Linked Data technologies and providing concrete security requirements of Linked Data applications. In this context, LDP WG has started to create a WG note on Access Control which aims to produce use cases for security scenarios of LDP applications that can be used as the input to later initiative that will be focused on developing standard security mechanisms for LDP applications.
The change history is up to the editors to insert a brief summary of changes, ordered by most recent changes first and with heading from which public draft it has been changed from.