This primer provides an introduction to Linked Data Platform (LDP), including the basic concepts of LDP including Linked Data Platform Resource (LDPR) and Linked Data Platform Container (LDPC) and their affordances, and a running example showing how an LDP client can interact with a LDP server in the context of read-write Linked Data application i.e. how to HTTP for accessing, updating, creating and deleting resources from servers that expose their resources as Linked Data.

This is the first draft of LDP Primer Note of W3C LDP WG.

Introduction

Linked Data is a universal approach for handling data which fundamentally includes the notion linking between data items. Much like the Web is giant network of interlinked documents for a human reader, the graph of Linked Data in the Web is a data layer on top of which applications are delivered, information is modified, processed, visualized and shared.

Linked Data Platform specification discusses standard HTTP and RDF techniques and best practices that you should use, and anti-patterns you should avoid, when constructing clients and servers that read and write Linked Data resources.

The Primer aims to provide introductory examples and guidance in the use of the LDP protocol. For a systematic account 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 Document

The examples in this guide are given as a serialization of RDF graphs using the Turtle [[TURTLE]] and JSON-LD [[JSON-LD]] syntaxes of RDF.

The buttons below can be used to show or hide the available syntaxes.

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#"
       }	
      }
	

LDP concepts in a glance

The LDP consists of two main building blocks: Linked Data Platform Resource (LDPR) and Linked Data Platform Container (LDPC).

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]]

A server hosting LDPRs may manage two kinds of LDPRs, those resources who whose state is represented using RDF which are called LDP-RDF Sources (LDP-RS) and those using other formats which are called LDP-NonRDF Sources (LDP-NR) such as html files, images, other binary files, etc.

A FOAF document file of a person that could be a good example of an LDP-RDF Source. When creating LDP-RSs, it is recommended that they reuse existing vocabularies instead of inventing their own duplicate vocabulary terms. It is also recommended that LDP-RSs have at least one rdf:type set explicitly to make the representations more useful to client applications that don’t support inferencing. For example, a FOAF file of a person as shown in Example 1 can be a LDP-RSs if it conforms to lifecycle patterns and conventions in defined in LDP Specification. Following the LDP Best Practices and Guidelines [[LDP-BP]], it uses terms from Dublin Core [[DC-TERMS]], Friend of a Friend [[FOAF]] vocabularies.


			

An avatar image of a person hosted in the same LDP server could be an example of an LDP-NR. These non-RDF resources also conform to the lifecycle patterns and conventions defined in the LDP specification that are applicable to all LDPRs including non-RDF LDPRs such as they must have an Etags, and must support HEAD, OPTIONS operations.

Linked Data Platform Container (LDPC) is a specialization of an LDPR. An LDPC is a collection of same-subject, same-predicate triples which is uniquely identified by a URI that responds to client requests for creation, modification, and enumeration of its members. For example, may be a person wants to keep information about her friends organized as a collection of documents about those friends. This collection acts as an enumeration of links to existing documents that contain information about her friends and also can be used to create documents about new friends when necessary. Example 2 shows an example of an LDP Container.


			
				
			

There are three different types of LDP Containers defined in the LDP specification: Basic Containers, Direct Containers, and Indirect Containers. Example 2 shows the most simplest type that is LDP Basic Container. The other types of containers will be explained later in the primer.

Elements of the collection of which are denoted by ldp:contains predicate shows the information documents contained by the LDP Container. These elements does not have to be LDPRs. Any HTTP resource can be contained in an LDPC. For example,

	
			

Use cases that motivated LDP specification varies from just publishing a dataset as Linked Data with advanced features as pagination, providing read/write access to using Linked Data for application integration. The Linked Data Platform Use Cases and Requirements document provides a more detailed information on the use cases that motivated the LDP specification.

There will be several categories of systems implementing the LDP specification. Two main categories of the LDP servers include:

Generic / vanilla LDP servers
RDF storage systems that allow interacting with their resources by means of the LDP specification. These servers do not impose any restriction on LDPRs.
Application specific LDP severs
Systems exposing their data using the LDP specification. These systems impose restrictions on LDPRs since they have an underlying business logic and data model.

File System Example (LDP-RS / LDP-NR / LDP-BasicContainer)

This section provides a set of examples of examples using a file system like read / write data storage on the Web that uses a Linked Data Platform protocol. These examples will demonstrate the behaviour of LDPRs including both LDR-RSs (which have RDF representations) and LDP-NRs (which do not have RDF representations such as binary resources) and LDP Basic Containers. When you register in example data storage system, you will get your data storage space (a root Basic Container) where you can store all sort of web resources that are supported by Linked Data Platform such as RDF resources (LDP-RS) and binary resources (LDP-NR). Using this root Basic Container you can create new files (documents) and also child containers to organize the documents.

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 Not allowed
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 the above API description, {document*} is considered a non-Container. The child containers such as /{username}/{ldp-bc}/ or /{username}/**/{ldp-bc}/ behave similar to the root container /{username}/ except for that fact, deleting those child containers are allowed.

In this example, we will see how Alice, a user of this system, manages the read / write document storage using the LDP protocl.

First, Alice registers in the system and she is given a space that she can store her documents (She could use LDP protocol to register herself by POSTing to a container of users but that is out of scope of this example). When she registers she is informed that her document space is http://data.example.org/alice/.

Looking up a basic container (GET on an LDP-BC)

First Alice looks up her storage by retrieving the LDP Basic Container assigned to her. As it was just created, it is an empty container.

    GET /alice/ HTTP/1.1
    Host: example.org
    Accept: text/turtle
		
    HTTP/1.1 200 OK 
    Content-Type: text/turtle; charset=UTF-8
    Link: <http://www.w3.org/ns/ldp/Resource>; rel="type"
    Link: <http://www.w3.org/ns/ldp/BasicContainer>; rel="type"
    ETag: W/"123456789"
	
    @prefix dcterms: <http://purl.org/dc/terms/>.
    @prefix ldp: <http://www.w3.org/ns/ldp#>.
	
    <http://data.example.org/alice/> a ldp:Container, ldp:BasicContainer;
       dcterms:title "Alice’s data storage on the Web" .		
	

Discovering the affordances (OPTIONS on an LDP-BC)

Now, Alice wants to know what she can do with her document space. She can use the OPTIONS operation to find out what are the operations she can do with her LDP-BC.

 		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/Resource>; rel="type"
Link: <http://www.w3.org/ns/ldp/BasicContainer>; rel="type"
Content-Length: 0 
	

Looking at the response, Alice (Alice's LDP client) can discover 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).

Creating a RDF resource (POST an RDF resource to an LDP-BC)

Alice decides to create a FOAF profile for her using the LDP-BC by POSTing her FOAF personal profile document.

 
POST /alice/ HTTP/1.1
Host: data.example.org
Slug: foaf
Content-Type: text/turtle

@prefix dc: <http://purl.org/dc/terms/> .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .

<> a foaf:PersonalProfileDocument;
    foaf:primaryTopic <#me> ;
    dc:title "Alice’s FOAF file" .

<#me> a foaf:Person;
    foaf:name "Alice Smith"  .    
   
 
HTTP/1.1 201 Created
Location: /alice/foaf
Link: <http://www.w3.org/ns/ldp/Resource>; rel="type"
Content-Length: 0   
   

Creating a binary resource (POST an image to an LDP-BC)

Update a RDF LDP resource (PUT on an LDP-RS)

Deleting a resource (DELETE on an LDPR)

Bug Tracker Example (LDP-DirectContainer)

This section provides 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. 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. We can re-use simple domain vocabulary, e.g. has_bug or related, to express our data. LDP provides the additional interaction capability in the protocol to perform dynamic evolution of knowledge representation.

RESTful APIs are often documented by through listing valid operations operating on URLs described as templates. A RESTful API for a simple Bug Tracker system might be described as follows:

Path Method Description
/app/{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.
/app/{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 metainformation about a resource

Do we want to say something about suggested, user-friendly URIs ?

Creation

Continuing from the previous example, we can report a Bug against 'product1' by creating a Bug LDPR under the 'Product' LDPC. The client POSTs a representation of a Bug to the Bug Tracker LDPC.

The client POSTs a representation of a Bug to the Bug Tracker LDPC.

	
				

If the create is successful, the server responds with location of the newly created resource.

HTTP/1.1 201 Created
Location: /app/product1/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.


			

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.

						
			

Update

TODO - Description

TODO - Description

	
				

If the update is successful, the server will respond with a success status and a new etag.

HTTP/1.1 204 No Content 
ETag: W/"123456790"  

Deletion

TODO - Description

TODO - Description

 DELETE /app/product1/bug3 HTTP/1.1 
 Host: example.org
				

If the update is successful, the server will respond with a success status and a new etag.

 HTTP/1.1 204 No Content
 ETag: W/"123456790"  
				

Structural Manipulation

If the bug tracker allows creating new Products in the tracker, that can done by posting a representation of a new Product to the Bug Tracker container. In this example the client includes the necessary ldp membership properties making the new Product a container for Bug resources.

The status of the bug tracker before creating the new product.

	
			

The client POSTs a representation of a Product to the Bug Tracker LDPC.

	
				

If the create is successful, the server responds with location of the newly created resource.

HTTP/1.1 201 Created
Location: /app/product2
Content-Length: 0  
				

After creation of this new container, 'product2', the representation of the 'Tracker' container will be

	
				

and the 'product2' will have the following representation.

		
        	

Operation Discovery

Assuming that a user got the URL of the product by out of band means, a starting point would be to discover which operations can be performed on the product resource.

The client does an OPTIONS with the URI of a known product description resource.

OPTIONS /app/product1/ HTTP/1.1
Host: example.org 

If the product description resource is available, the server responds with the allowed HTTP operations on the product resource along with some other metadata.

HTTP/1.1 200 OK
Allow: OPTIONS,HEAD,GET,POST,PUT,PATCH
Accept-Post: text/turtle, application/ld+json 
Accept-Patch: example/patch
Link: <http://www.w3.org/ns/ldp/Resource>; rel="type"
Link: <?nonMemberProperties>;rel="http://www.w3.org/ns/ldp#nonMemberResource"
Content-Length: 0

According to the response, HTTP operations {OPTIONS,GET,POST,PUT,PATCH} are allowed on the product description resource. In addition to the allowed operations, Accept-Post and Accept-Patch provides which media types are supported by respective operations. The rel="type" Link header advertises that this is resource supports LDP protocol and the the rel="ldp:nonMemberResource" provides a link to the non-member resource of this product description.

Pagination

It sometimes happens that a resource is too large to reasonably transmit its representation in a single HTTP response. For example, if the bug resource in our example includes comments, It might happen that it may be become too large. To address this problem, LDPRs should support a technique called Paging.

If a client does a get on an LDPR that supports paging, it will be redirected to the first page of the resource.

	GET /app/product1/bug3 HTTP/1.1
	Host: example.org 
					
	HTTP/1.1 303 See Other
	Location: /app/product1/bug3?firstpage
					

Alternatively if the client wants to know in advance whether the resource is paged or not, it can do an OPTIONS request on the LDPR URI

	OPTIONS /app/product1/bug3 HTTP/1.1
	Host: example.org 
					

If the resource is paged, the response contains a HTTP Link header with rel="first"; and the target URI of that header would be the URL of the first page resource.

	HTTP/1.1 200 OK
	Allow: OPTIONS,HEAD,GET,PUT,PATCH
	Accept-Patch: example/patch
	Link: <http://www.w3.org/ns/ldp/Resource>; rel="type"
	Link: </app/product1/bug3?firstpage>; rel="first"
	Content-Length: 0
					

After knowing the URL of the first page resource, the client can retrieve it using a HTTP GET

	GET /app/product1/bug3?firstpage HTTP/1.1
	Host: example.org 
	Accept: text/turtle; charset=UTF-8
					
	
					

The first page contains a link to the second page with LDPR as the subject, ldp:nextPage as the predicate and the subsequent page as the object.

The second page can be retrieved the same way as the first page was retrieved.

	GET /app/product1/bug3?secondPage HTTP/1.1
	Host: example.org 
	Accept: text/turtle; charset=UTF-8
					
	
					

The last page of resource contains with LDPR as the subject, ldp:nextPage as the predicate and the rdf:nil as the object.

Ordering

There are many cases where an ordering of the members of the container is important.

	GET /app/product1?firstPage HTTP/1.1
	Host: example.org 
	Accept: text/turtle; charset=UTF-8
					
			
				

Binary resources

Creating a binary resource

We have an LDPC which we can use to create binary resources

	
			

The client POSTs a binary resource to the LDPC

POST /app/product1/bug3/attachments/ HTTP/1.1
Host: example.org
Content-Type: image/png
Slug: login-page.png
Content-Length: 1254

#### binary data #####		
					

If the create is successful, the server it responds with a Location header and a Link header to the automatically created metadata LDPR.

HTTP/1.1 201 Created
Location: /app/product1/bug3/attachments/login-page.png
Link: </app/product1/bug3/attachments/1>; rel="meta"
Content-Length: 0
			

After the creation, LDPC representation looks like

	
			
Accessing the binary resource

The client can retrieve the binary resource by doing a GET on the binary resource URI.

GET /app/product1/bug3/attachments/login-page.png  HTTP/1.1
Host: example.org
Accept: image/png
	

LDPR server responds with

HTTP/1.1 200 OK 
Content-Type: image/png
Link: </app/product1/bug3/attachments/1>; rel="meta"
ETag: W/"123456789"

#### binary data ##### 
						
						
Accessing the metadata about the binary resource

The client can retrieve the metadata of the binary resource by doing a GET on the metadata-LDPR URI.

GET /app/product1/bug3/attachments/1
Host: example.org
Accept: text/turtle 
	

LDPR server responds with

				
				
Updating the metadata about the binary resource

TODO

	
				   

LDPR server responds with

HTTP/1.1 204 No Content 
ETag: W/"123456790"
	
Deleting the binary resource

TODO

 DELETE /app/product1/bug3/attachments/login-page.png HTTP/1.1
 Host: example.org 
	
HTTP/1.1 204 No Content
 ETag: W/"123456790" 
	
GET /app/product1/bug3/attachments/login-page.png HTTP/1.1
 Host: example.org 
	
HTTP/1.1 410 Gone 
	
 GET /app/product1/bug3/attachments/1
 Host: example.org 
	
HTTP/1.1 410 Gone 
	

Advanced Examples

Uses of membership{Subject,Predicate,Object} predicates

In most of the previous examples we kept the ldp:membershipSubject as the LDPC itself and ldp:membershipObject as the ldp:MemberSubject. However, these predicates can be used to change the semantics of the membership relationship in LDPCs.

TO DO: A small note on document vs Thing separation linking to Web Arch, , Cool URIs, URLs in Data.

If the separation between real world resource and information is important, the product description of the previous Bug Tracker example can be alternatively designed as following.

	
					

In the above example, the product description information resource is explicitly seperated from the real world product resource. Now the RDF representation contains information about both the information resource that is identified by the URI </app/product1/> and the real world resource identified by the URI </app/product1/#it>.

With this seperation, now the ldp:membershipSubject of the container is not the container URI itself but </app/product1/#it>. The effect of these is that membership relation triples added when new resources are POSTed to this container will now have the subject </app/product1/#it> not the container URI. Further, ldp:membershipObject of this container is foaf:primaryTopic. Thus, the object of the membership triple will not be the newly created resource but the foaf:primaryTopic defined inside that newly created resource as shown in the following example.

	
					

And the server will respond with the URI of the newly created information resource in the Location header.

HTTP/1.1 201 Created
Location: /app/product1/67
Content-Length: 0 					
					

After the resource creation, the representations of the LDPC and newly created LDPR would be


					

							
				

ldp:membershipPredicateInverse predicate

In sometimes the membership relationship can defined in a way such that the container is becomes the object of the membership triple. For example, in our example, if the membership triple was like < bug, bt:relatedProduct, product > the product container would look like

	
	    

TODO - Find a better example

Resource Inlining

TODO - Description

TODO - Description


				

				
			

Member Inlining

Security

Mention a little bit about security

LDP Implementations

A list of implementations that plan to be LDP compliant is available in the LDP Implementations wiki page. LDP Implementation report provides the coverage of the specification by each LDP implementation.

What To Read Next

The primer only provide an overview of the Linked Data Platform specifications. LDP WG has produced following documents that contribute to the Linked Data Platform specification.

Change History

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.