Warning:
This wiki has been archived and is now read-only.

Examples

From Linked Data Platform
Jump to: navigation, search

1 Material from Scope & Motivation

There has been much less focus on the potential of Linked Data as a model for managing data on the web - the majority of the Application Programming Interfaces (APIs) available on the Internet for creating and updating data follow a Remote Procedure Call (RPC) model rather than a Linked Data model.

If Linked Data were just another model for doing something that RPC models can already do, it would be of only marginal interest. Interest in Linked Data arises from the fact that applications with an interface defined using Linked Data can be much more easily and seamlessly integrated with each other than applications that offer an RPC interface. In many problem domains, the most important problems and the greatest value are found not in the implementation of new applications, but in the successful integration of multiple applications into larger systems.

Some of the features that make Linked Data exceptionally well suited for integration include:

  • A single interface – defined by a common set of HTTP methods – that is universally understood and is constant across all applications. This is in contrast with the RPC architecture where each application has a unique interface that has to be learned and coded to.
  • A universal addressing scheme – provided by HTTP URLs – for both identifying and accessing all “entities”. This is in contrast with the RPC architecture where there is no uniform way to either identify or access data.
  • A simple yet extensible data model – provided by RDF – for describing data about a resource in a way which doesn’t require prior knowledge of vocabulary being used.

Experience implementing applications and integrating them using Linked Data has shown very promising results, but has also demonstrated that the original four rules defined by Tim Berners-Lee for Linked Data are not sufficient to guide and constrain a writable Linked Data API. As was the case with the original four rules, the need generally is not for the invention of fundamental new technologies, but rather for a series of additional rules and patterns that guide and constrain the use of existing technologies in the construction of a LINKED-DATA-PLATFORM to achieve interoperability.

The following list illustrates a few of the issues that require additional rules and patterns:

  • What URLs do I post to in order to create new resources?
  • How do I get lists of existing resources, and how do I get basic information about them without having to access each one?
  • How should I detect and deal with race conditions on write?
  • What media-types/representations should I use?
  • What standard vocabularies should I use?
  • What primitive data types should I use?

2 Other User Stories

2.1 RESTful Interactions

REST's main focus is on building interactions around the exchange transfer between clients and servers. For this to work, it must be possible to define and communicate expectations for certain state transfers. In this gist the discussion centers around book orders, but pretty much any interaction in a SOA context could be used: some interaction requires a specific state transfer between client and server, and there must be a way how this state transfer is

  • captured in the context of a bigger interaction flow (what a media type defines on the web), and
  • expressed by means of expectations/constraints that apply to a specific representations, so that a server can validate against those expectations/constraints, and only accept those representations which satisfy the expectations/constraints (what often is done with a combination of schemas and prose in the context of a media type's conversation).

"What Are Linked Data Services?" describes these requirements as the "service surface" that needs to be defined by any platform that is providing some sort of services. This becomes particularly important in any kind of loosely coupled scenario, where servers/services cannot trust clients to always do the "right thing" or "behave cooperatively". instead, the platform must provide support so that misbehaving and adversarial clients can be dealt with effectively, and that means that the "service contract" needs to define the service surface based on the state representations that are acceptable in the context of the use case that is addressed by the service, so that anything else can be easily rejected.

2.2 Hosting POSTed Resources

<http://dev.example/bugs> is a factory resource for creating new bugs (well, documenting existing bugs). It accepts <Bug>s of the form:

 _:newBug a <Bug> ;
          <product> <http://products.example.com/gun> ;
          <issueText> "kills people" ;
          dc:author "Bob" ;
          dc:date "2012-07-04T23:54"^^xsd:dateTime

By this definition "hosting" means changing _:newBug to <http://dev.example/bug/7>. LDP doesn't provide any guidance around that.

2.3 Constrained Devices

For a detailed description of application scenarios for constrained devices see a separate document kindly compiled by Myriam Leggieri.

3 Linked Data Platform Examples

In the scenarios that follow, there are a number of commonly used namespace prefixes:

@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>.
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>.
@prefix bp: <http://example.com/ns/basicProfile#>.
@prefix xsd: <http://www.w3.org/2001/XMLSchema#>.
@prefix foaf: <http://xmlns.com/foaf/0.1/>.
@prefix wdrs: <http://www.w3.org/2007/05/powder-s#>.
@prefix skos <http://www.w3.org/2004/02/skos/core#>.
@prefix dcat: <http://www.w3.org/ns/dcat#>.
@prefix dc: <http://purl.org/dc/elements/1.1/#>.
@prefix dcterms: <http://purl.org/dc/terms/>.
@prefix cs: <http://purl.org/vocab/changeset/schema#>.
@prefix eg: <http://example.com/>.
 

3.1 Create a resource within a container using POST/PUT

An HTTP POST to the target container creates a new resource within that container, returning the URI of the new resource. A subsequent PUT to this URI adds content. This approach is useful for clients that cannot use the null relative URI form.

  1. The client requests an HTTP POST on a URI identifying an LDP Container.
  2. The server creates a new resource.
  3. If the creation succeeded, the server answers with 201 Created and the location of the created resource.
  4. The client requests an HTTP PUT on the new resource URI including the RDF content and appropriate Content-Type.
  5. The server answers 204 No Content to confirm the PUT.

3.2 Get RDF representation of an information resource (UC-LDPR1-S1)

In the basic case, the requested resource is an information resource:

  1. The client requests an HTTP GET on a URI identifying an LDP resource, with an accept header requesting information in the required RDF format.
  2. The server answers with 200 OK and returns an RDF representation of the resource in the requested format.

Based on Maintaining Social Contact Information, a user should be able to read contact details so that they are able to interact with a contact. An LDP holds social contact information about Alice. In this example the contact details make no distinction between resources and the people they describe. Resource http://example.com/people/Alice delineates the following RDF model. A Request for this resource returns an RDF representation in the desired format which could be Turtle or another RDF serialisation.

@prefix : <http://example.com/people/>.

<> a foaf:Person;
   rdfs:label "Alice";
   foaf:mbox <mailto:alice@example.com>.
 

A data source holds social contact information about Alice and Bob, and the client requests contact details for Alice. In this example the contact details make no distinction between the information resources and the people they describe.

@prefix : <http://example.com/people/>.

:alice a foaf:Person;
   rdfs:label "Alice";
   foaf:mbox <mailto:alice@example.com>;
   foaf:knows :bob.

:bob a foaf:Person;
   rdfs:label "Bob";
   foaf:mbox <mailto:bob@example.com>.
 

The resource identified by <http://example.com/people/alice> is requested below:

GET http://example.com/people/alice HTTP/1.1
Host: example.com
Accept: text/turtle
 

The response describes Alice, but not Bob :

HTTP/1.1 200 OK 
Content-Type: text/turtle
ETag: W/"123456789"

@prefix : <http://example.com/people/>.

:alice a foaf:Person;
   rdfs:label "Alice";
   foaf:mbox <mailto:alice@example.com>;
   foaf:knows :bob.
 

3.3 Get RDF description of a non-information resource

In the case that the URI is unresolvable, the LDP server may redirect the URI to a resolvable LDPR.

  1. The client requests an HTTP GET on a URI identifying a non-information resource.
  2. The server answers with 303 See Other, redirecting the client to an LDPR.
  3. The client requests an HTTP GET on the LDPR, with an accept header requesting information in the required RDF format.
  4. The server answers with 200 OK and the requested RDF representation.

The data source holds social contact information about Alice and Bob, and the client requests contact details for Alice. The wdrs:describedby relationship introduces a distinction between things and their descriptions.

@prefix : <http://example.com/people/>.

:alice a foaf:Person;
   rdfs:label "Alice";
   foaf:mbox <mailto:alice@example.com>;
   foaf:knows :bob;
   wdrs:describedby :alice.rdf.

:bob a foaf:Person;
   rdfs:label "Bob";
   foaf:mbox <mailto:bob@example.com>;
   wdrs:describedby :bob.rdf.
 

In this case, the <http://example.com/people/alice> resource is redirected to it's descriptive URI, <http://example.com/people/alice.rdf>.

GET http://example.com/people/alice HTTP/1.1
Host: example.com
Accept: text/turtle
 

The first response is the redirection to <http://example.com/people/alice.rdf>.

HTTP/1.1 303 See Other
Location: http://example.com/people/alice.rdf
 

The client requests a GET of the returned location:

GET http://example.com/people/alice.rdf HTTP/1.1
Host: example.com
Accept: text/turtle
 

The response includes information about <http://example.com/people/alice.rdf> and anything it describes.

HTTP/1.1 200 OK 
Content-Type: text/turtle
ETag: W/"123456789"

@prefix : <http://example.com/people/>.

:alice a foaf:Person;
   rdfs:label "Alice";
   foaf:mbox <mailto:alice@example.com>;
   foaf:knows :bob;
   wdrs:describedby :alice.rdf.
 

3.4 Replace the current resource in full using PUT (UC-LDPR2-S1)

A data source holds social contact information about Alice, and the client wishes to update the email contact details for her.

Replace the entire persistent state of the identified resource with the entity representation in the body of the request. The scenario covers a typical sequence of events where the client first GETs the current state prior to the update.

  1. The client requests an HTTP GET on a URI identifying an LDP Resource, with an accept header requesting information in the required RDF format.
  2. The server answers with 200 OK and returns the requested representation, describing the resource in the requested format, including the current entity tag.
  3. The client requests an HTTP PUT on the same URI with RDF representing the updated resource, including an If-Match header with the last known entity tag, and the appropriate Content-Type.
  4. If no entity tag is supplied in the request, the server should respond with 409 Conflict.
  5. If the update succeeds, the server responds with 204 No Content.
  6. Otherwise, the server responds with 412 Precondition Failed.
@prefix : <http://example.com/people/>.

:alice a foaf:Person;
   rdfs:label "Alice";
   foaf:mbox <mailto:alice@example.com>.
 

The client performs an initial HTTP GET to establish the current state of the resource.

GET http://example.com/people/alice HTTP/1.1
Host: example.com
Accept: text/turtle
 

As well as the RDF state, the client saves the entity tag.

HTTP/1.1 200 OK 
Content-Type: text/turtle
ETag: W/"123456789"

@prefix : <http://example.com/people/>.

:alice a foaf:Person;
   rdfs:label "Alice";
   foaf:mbox <mailto:alice@example.com>.
 

The resource identified by <http://example.com/people/alice> is updated below, including the current entity tag:

PUT http://example.com/people/alice HTTP/1.1
Host: example.com
Content-Type: text/turtle
If-Match: W/"123456789"

@prefix : <http://example.com/people/>.

:alice a foaf:Person;
   rdfs:label "Alice";
   foaf:mbox <mailto:alice@example.org>.
 

The response confirms the update:

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

3.5 Selective update of the resource using PATCH (UC-LDPR2-S2)

A data source holds social contact information about Alice, and the client wishes to update the email contact details for her. The client may perform an HTTP GET to get the current state.

GET http://example.com/people/alice HTTP/1.1
Host: example.com
 

The response describes social contact information about Alice.

HTTP/1.1 200 OK 
ETag: W/"123456789"

@prefix : <http://example.com/people/>.

:alice a foaf:Person;
   rdfs:label "Alice";
   foaf:mbox <mailto:alice@example.com>.
 

The resource identified by <http://example.com/people/alice> is updated below, including the current entity tag. The PATCH is defined here using a changeset. see <http://docs.api.talis.com/getting-started/changesets>.

PATCH http://example.com/people/alice HTTP/1.1
Host: example.com
Content-Type: text/turtle
If-Match: W/"123456789"

@prefix : <http://example.com/people/>.

<change1>
  a cs:ChangeSet ;
  cs:subjectOfChange :alice ;
  cs:createdDate "2012-01-01T00:00:00Z" ;
  cs:changeReason "Update mbox" ;
  cs:removal [
    a rdf:Statement ;
    rdf:subject :alice ;
    rdf:predicate foaf:mbox ;
    rdf:object <mailto:alice@example.com> .
  ] ;
  cs:addition [
    a rdf:Statement ;
    rdf:subject :alice ;
    rdf:predicate foaf:mbox ;
    rdf:object <mailto:alice@example.org> .
  ] .
 

The response confirms the update, returning the modified resource description.

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

3.6 Retrieve resource entity tag using HEAD (UC-LDPR3-S1)

The client requests an HTTP HEAD to establish the current state of the resource.

  1. The client requests an HTTP HEAD of a URI identifying an LDP Resource.
  2. The server answers with the current entity tag for the resource, and allowed operations.
@prefix : <http://example.com/people/>.

:alice a foaf:Person.
 

The client requests an HTTP HEAD to establish the current state of the resource.

HEAD http://example.com/people/alice HTTP/1.1
Host: example.com
 

The response includes the entity tag and allowed operations.

HTTP/1.1 204 No Content
Allow: GET, PUT, POST, HEAD, PATCH, DELETE 
ETag: W/"123456789"
 

3.7 Conditional GET request (UC-LDPR3-S2)

The client performs a conditional HTTP GET on a resource using 'If-none-Match'. If the RDF representation hasn't changed the response is a 304 'Not Modified' with no entity body.

  1. The client requests an HTTP HEAD on a URI identifying an LDP Resource.
  2. If the resource hasn't changed, the server answers with HTTP response code 304 'Not Modified' and returns the current entity tag for the resource.
  3. Otherwise, the server returns 200 OK, the RDF representation and current entity tag.

Determine if the contact for Alice has changed.

@prefix : <http://example.com/people/>.

:alice a foaf:Person.
 

The client requests an HTTP GET to determine if it has changed.

GET http://example.com/people/alice HTTP/1.1
Host: example.com
Accept: text/turtle
If-none-Match: W/"123456789"
 

Assuming the resource is unchanged, the response includes the entity tag.

HTTP/1.1 304 Not Modified
ETag: W/"123456789"
 

3.8 Delete resource (UC-LDPR4-S1)

The client requests an HTTP DELETE of a resource.


In practice, sensitive data will be subject to access control as described in user-story LDP and Authentication/Authorization. In this scenario authentication is based on Web Access Control. The user authenticates to the LDP server using FOAF+SSL, returning a WebID - a URI identifying the user. We assume the LDP holds an RDF Access Control List (ACL) expressed in the Basic Access Control ontology. This is used to determine whether or not the user is authorized to perform the operation, in this case a deletion (a write operation). In the ACL fragment below the agent identified as <http://example.com/card#i> is permitted access to delete <resourceX>.

@prefix acl: <http://www.w3.org/ns/auth/acl#> .

[acl:accessTo <resourceX>; acl:mode acl:Read, acl:Write; acl:agent <http://example.com/card#i>].
 
  1. The client requests an HTTP DELETE on a URI identifying an LDP Resource.
  2. If the request includes an 'If-Match' header then compare this entity tag with the current entity tag.
  3. If the resource is successfully deleted, the server answers 204 No Content, confirming deletion.
  4. Otherwise answer with 412 Precondition Failed.

As HTTP DELETE is idempotent it is not an error to delete a resource that has already been deleted.

Delete the contact for Alice.

@prefix : <http://example.com/people/>.

:alice a foaf:Person.
 

The client requests an HTTP DELETE.

DELETE http://example.com/people/alice HTTP/1.1
Host: example.com
 

Assuming the resource is successfully deleted, the response includes the entity tag.

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

3.9 Create a new resource using PUT (UC-LDPR5-S1)

Create a new resource based on the RDF in the request body using PUT.

  1. The client requests an HTTP PUT at the target URI with RDF representing the new resource, with the appropriate Content-Type.
  2. If the creation succeeds, the server responds with 201 Created and the entity tag.
  3. Otherwise, the server responds with 409 Conflict.

The client wishes to create a new contact for Carol.

The client performs an initial HTTP GET to establish the current state of the resource. We assume that there is no pre-existing resource at the address.

PUT http://example.com/people/carol HTTP/1.1
Host: example.com
Content-Type: text/turtle

<> a foaf:Person;
   rdfs:label "Carol";
   foaf:mbox <mailto:carol@example.com>.
 

The confirmation includes the entity tag.

HTTP/1.1 201 Created
ETag: W/"987654321"
 

3.10 Create a new resource using PATCH (UC-LDPR5-S2)

Create a new resource using PATCH to insert the relevant triples.

  1. The client requests an HTTP PATCH on the target URI with RDF representing the new resource, and the appropriate Content-Type.
  2. If the creation succeeds, the server responds with 201 Created and the entity tag.
  3. Otherwise, the server responds with 409 Conflict.

3.11 List contained resources but not their properties (UC-LDPC1-S1)

In this scenario, the server returns references to the full membership of the container in a single request. It is implementation specific whether or not the server returns any additional information about each member.

  1. The client requests an HTTP GET on a URI identifying an LDP Container. The accept header specifies the required media type for the returned RDF serialization.
  2. If the size of the container is too large, the LDP may redirect the request to the paginated collection, answering 307 Moved temporarily with the Location header set.
  3. Otherwise, the server answers with 200 OK and returns the RDF representation in the requested format.

This scenario is based on the user-story #Maintaining Social Contact Information. The data source holds social contact information in a container called /mycontacts (an information resource).

@prefix : <http://example.com/people/>.

eg:mycontacts a bp:Container;
   rdfs:member
      :alice,
      :bob.

:alice a foaf:Person;
   rdfs:label "Alice";
   foaf:mbox <mailto:alice@example.com>;
   foaf:knows :bob.

:bob a foaf:Person;
   rdfs:label "Bob";
   foaf:mbox <mailto:bob@example.com>.
 

The user requests information about the container resource.

GET http://example.com/mycontacts HTTP/1.1
Host: example.com
Accept: text/turtle
 

The response should include information about the container and references to contained resources, but not information about them.

HTTP/1.1 200 OK 
Content-Type: text/turtle
ETag: W/"123456790"

@prefix : <http://example.com/people/>.

eg:mycontacts a bp:Container;
   rdfs:member
      :alice,
      :bob.
 

3.12 Paginated list of contained resources and their properties (UC-LDPC1-S2)

In many applications, it is desirable for the client to be able to get full descriptions about multiple members of a container, in a single request. However, if the membership is large, a single representation containing descriptions of all members may be onerously large. Paging allows different subsets of the membership to returned in a sequence of requests.

  1. The client requests an HTTP GET on a URI identifying an LDP Container, qualified with the requested page (eg. ?firstpage). The accept header specifies the required media type for the returned RDF serialization.
  2. If an 'If-Match' header is supplied, the entity tag should be compared with the curent container entity tag.
  3. The members are sorted according to some criteria, and the relevant subset of properties are listed.
  4. The server answers with 200 OK and returns the RDF representation of the subset in the requested format.
  5. An opaque URI in the returned representation identifies the next page.

Example: The data source holds social contact information in a container resource called /mycontacts.

@prefix : <http://example.com/people/>.

eg:mycontacts a bp:Container;
   rdfs:member
      :alice,
      :bob,
      :carol.

:alice a foaf:Person;
   rdfs:label "Alice";
   foaf:mbox <mailto:alice@example.com>;
   foaf:knows :bob.

:bob a foaf:Person;
   rdfs:label "Bob";
   foaf:mbox <mailto:bob@example.com>.
   
:carol a foaf:Person;
   rdfs:label "Carol";
   foaf:mbox <mailto:carol@example.com>.
 

The user requests the first page of information about the container membership. In this example the page size is 2.

GET http://example.com/mycontacts?firstPage HTTP/1.1
Host: example.com
Accept: text/turtle
 

The response should include information about the container and the relevant subset of the membership and their properties.

HTTP/1.1 200 OK 
Content-Type: text/turtle
ETag: W/"123456790"

@prefix : <http://example.com/people/>.

eg:mycontacts a bp:Container;
   rdfs:member
      :alice,
      :bob.
	  
<> a bp:Page;
   bp:pageOf eg:mycontacts;
   bp:nextPage eg:mycontacts?p=2.
	  
:alice a foaf:Person;
   rdfs:label "Alice";
   foaf:mbox <mailto:alice@example.com>;
   foaf:knows :bob.

:bob a foaf:Person;
   rdfs:label "Bob";
   foaf:mbox <mailto:bob@example.com>.
 

The follow-up request for the next page may include the container entity tag to ensure consistent pagination.

GET http://example.com/mycontacts?p=2 HTTP/1.1
Host: example.com
Accept: text/turtle
If-Match: W/"123456790"
 

The response includes the remaining contact.

HTTP/1.1 200 OK 
Content-Type: text/turtle
ETag: W/"123456790"

@prefix : <http://example.com/people/>.

eg:mycontacts a bp:Container;
   rdfs:member
      :carol.

<> a bp:Page;
   bp:pageOf eg:mycontacts;
   bp:nextPage rdf:nil.
	  
:carol a foaf:Person;
   rdfs:label "Carol";
   foaf:mbox <mailto:carol@example.com>.
 

3.13 Create a resource within a container

An HTTP POST to the target container, including a representation of the new resource, creates a new resource within that container.

Assumptions

  • The document base URI is the URI of the created resource.
  1. The client requests an HTTP POST on a URI identifying an LDP Container, including the RDF content with appropriate Content-Type.
  2. The server creates a new resource with the defined properties and relationships. The resource URI defines the document base of the posted RDF representation.
  3. If the creation succeeded, the server answers with 201 Created and the location of the created resource.

Assume we have an existing container resource with a defined membership predicate.

<http://example.com/contacts/> a bp:Container;
  bp:membershipPredicate rdfs:member .
 
POST http://example.com/contacts/ HTTP/1.1
Host: example.com
Content-Type: text/turtle

 <> a foaf:PersonalProfileDocument;
   foaf:primaryTopic <#me> .

 <#me> a foaf:Person;
     foaf:name "Henry" .
 

The response confirms creation of the new resource at the indicated location.

HTTP/1.1 201 Created
Location: http://example.com/contacts/a0001
ETag: W/"1234567890"
 

3.14 Create a container under another container (UC-LDPC2-S2)

Helios bugs allow bugs to have sub-issues using the membership predicate <helios_bt:hasSubIssue>. The new member can be identified as a Container.

POST http://example.com/bugtracker HTTP/1.1
Host: example.com
Content-Type: text/turtle

@prefix helios_bt: <http://heliosplatform.sourceforge.net/ontologies/2010/05/helios_bt.owl#>.

<> rdfs:member [
      a helios_bt:BugtrackerIssue, bp:Container;
      dc:identifier	"58366";
      dc:type	"bug";
      helios_bt:isInBugtracker eg:bugtracker ;

      bp:membershipPredicate helios_bt:hasSubIssue .
   ]
 

The response confirms creation of the new resource at the indicated location.

HTTP/1.1 201 Created
Location: http://example.com/bugtracker/a0002
ETag: W/"1234567891"
 


3.15 Retrieve non-member properties of a container (UC-LDPC3-S1)

In this scenario, the server returns references to the full membership of the container in a single request. It is implementation specific whether or not the server returns any additional information about each member.

  1. The client requests an HTTP GET on a URI identifying an LDP Container qualified with ?non-member-properties. The accept header specifies the required media type for the returned RDF serialization.
  2. The server answers with 200 OK and returns the RDF representation in the requested format.

This scenario is based on the user-story #Data_catalogs and Data Catalog Vocabulary (DCAT). The data source holds catalog information in a container called /mycatalog (a container resource).

@prefix : <http://example.com/>.

 :mycatalog a bp:Container;
   bp:membershipSubject :catalog;
   bp:membershipPredicate dcat:record.

 :catalog a dcat:Catalog ;
    dcterms:title "Example catalog" ;
    dcat:record :record-001.
	   
 :record-001 a dcat:CatalogRecord ;
    foaf:primaryTopic :dataset-001 ;
    dcterms:issued "2011-12-11"^^xsd:date.
	   
 :dataset-001 a dcat:Dataset ;
    dcterms:title "Example dataset" .
 

The user requests information about the container resource /mycatalog.

GET http://example.com/mycatalog?non-member-properties HTTP/1.1
Host: example.com
Accept: text/turtle
 

The response should include information about the container.

HTTP/1.1 200 OK 
Content-Type: text/turtle
ETag: W/"9999999999"

@prefix : <http://example.com/dcat/>.

 :mycatalog a bp:Container;
   bp:membershipSubject :catalog;
   bp:membershipPredicate dcat:record.

 :catalog a dcat:Catalog ;
    dcterms:title "Example catalog" .
 

3.16 Place an existing resource in a container (UC-LDPC4-S1)

Add a named resource to a container using HTTP PATCH. There are many reasons why we might wish to add a named resource to a container. The same resource may be added to multiple containers, or we may simply want to create sensible names for things that people can understand intuitively (rather than a machine generated name) (see [1]).

  1. The client requests an HTTP PATCH on the container (or the resource) including the insertion of an explicit membership relationship between a container membership subject and an existing resource. The request should indicate the appropriate Content-Type.
  2. The server answers 204 No Content to confirm the patch.

Example: This example is based on #Library Linked Data use-cases LLD-UC, specifically Subject Search.

@prefix scheme : <http://example.com/concept-scheme/>.

scheme:subject-heading a skos:ConceptScheme, bp:Container.
 

The client wishes to insert a new concept into the scheme.

PATCH http://example.com/concept-scheme/subject-heading HTTP/1.1
Host: example.com
Content-Type: text/turtle

@prefix : <http://example.com/>.
@prefix scheme : <http://example.com/concept-scheme/>.
@prefix concept : <http://example.com/concept/>.

<change1>
  a cs:ChangeSet ;
  cs:subjectOfChange scheme:subject-heading ;
  cs:createdDate "2012-01-01T00:00:00Z" ;
  cs:changeReason "Update concept scheme" ;
  cs:addition [
    a rdf:Statement ;
    rdf:subject concept:Outer+space--Exploration ;
    rdf:predicate skos:inScheme ;
    rdf:object scheme:subject-heading .
  ] .
 

The response indicates the revised state of the container resource.

HTTP/1.1 200 OK 
ETag: W/"111111111"

@prefix scheme : <http://example.com/concept-scheme/>.
@prefix concept : <http://example.com/concept/>.

scheme:subject-heading a skos:ConceptScheme, bp:Container.

concept:Outer+space--Exploration skos:inScheme scheme:subject-heading.
 

3.17 Place resource in more than one container (UC-LDPC4-S2)

SNOMED CT allows concepts with more than one parent that don't fall into a lattice. In the example below, we add the same concept to two different container concepts (via skos:narrowerTransitive). The example uses skos:narrowerTransitive to elide intervening concepts.

@prefix concept : <http://example.com/concept/>.

concept:TissueSpecimen a skos:Concept, bp:Container ;
   bp:membershipPredicate skos:narrowerTransitive .
   
concept:SpecimenFromTrunk a skos:Concept, bp:Container ;
   bp:membershipPredicate skos:narrowerTransitive .
 

We now wish to assert a new concept concept:TissueSpecimenFromHeart which falls under both concepts.

PATCH http://example.com/concept/TissueSpecimen HTTP/1.1
Host: example.com
Content-Type: text/turtle

@prefix : <http://example.com/>.
@prefix concept : <http://example.com/concept/>.

<change1>
  a cs:ChangeSet ;
  cs:subjectOfChange concept:TissueSpecimen ;
  cs:createdDate "2012-01-01T00:00:00Z" ;
  cs:changeReason "Update concept hierarchy" ;
  cs:addition [
    a rdf:Statement ;
    rdf:subject concept:TissueSpecimen ;
    rdf:predicate skos:narrowerTransitive ;
    rdf:object concept:TissueSpecimenFromHeart .
  ] ;
  cs:addition [
    a rdf:Statement ;
    rdf:subject concept:TissueSpecimenFromHeart ;
    rdf:predicate rdf:type ;
    rdf:object skos:Concept .
  ] ; 
 
 
HTTP/1.1 200 OK 
ETag: W/"1234567890"

@prefix concept : <http://example.com/concept/>.

concept:TissueSpecimen a skos:Concept, bp:Container ;
   bp:membershipPredicate skos:narrowerTransitive ;
   skos:narrowerTransitive concept:TissueSpecimenFromHeart .
 

The second container is patched separately.

 
PATCH http://example.com/concept/SpecimenFromTrunk HTTP/1.1
Host: example.com
Content-Type: text/turtle

@prefix : <http://example.com/>.
@prefix concept : <http://example.com/concept/>.

<change1>
  a cs:ChangeSet ;
  cs:subjectOfChange concept:SpecimenFromTrunk ;
  cs:createdDate "2012-01-01T00:00:00Z" ;
  cs:changeReason "Update concept hierarchy" ;
  cs:addition [
    a rdf:Statement ;
    rdf:subject concept:SpecimenFromTrunk ;
    rdf:predicate skos:narrowerTransitive ;
    rdf:object concept:TissueSpecimenFromHeart .
  ] .
 

The response confirms the addition.

HTTP/1.1 200 OK 
ETag: W/"1234567891"

@prefix concept : <http://example.com/concept/>.

concept:SpecimenFromTrunk a skos:Concept, bp:Container ;
   bp:membershipPredicate skos:narrowerTransitive ;
   skos:narrowerTransitive concept:TissueSpecimenFromHeart .
 


3.18 Remove a LDPR from a container but not delete it from the system (UC-LDPC4-S3)

Selectively remove membership properties from a container resource resource.

  1. The client requests an HTTP GET of a URI identifying an LDP container.
  2. The server answers with an RDF representation of the container membership and the entity tag.
  3. The client requests an HTTP PATCH on the container describing the removal of the membership relation between the container and the subordinate resource.
  4. The server answers 204 No Content to confirm the patch.

An HTTP GET is used to retrieve the initial state of the container.

 
GET http://example.com/planets HTTP/1.1
Host: example.com
Accept: text/turtle
 

The response lists the container membership and entity tag.

HTTP/1.1 200 OK 
Content-Type: text/turtle
ETag: W/"1234567890"
 
eg:planets a skos:Collection, bp:Container;
   skos:prefLabel "The planets"@en;
   skos:member eg:Mercury;
   skos:member eg:Venus;
   skos:member eg:Earth;
   skos:member eg:Mars;
   skos:member eg:Jupiter;
   skos:member eg:Saturn;
   skos:member eg:Uranus;
   skos:member eg:Neptune;
   skos:member eg:Pluto.
 

An HTTP PATCH is used to directly edit membership.

PATCH http://example.com/planets HTTP/1.1
Host: example.com
Content-Type: text/turtle
If-Match: W/"1234567890"

<change1> a cs:ChangeSet ;
  cs:subjectOfChange eg:planets ;
  cs:createdDate "2012-01-01T00:00:00Z" ;
  cs:changeReason "Pluto is a dwarf planet" ;
  cs:removal [
    a rdf:Statement ;
    rdf:subject eg:planets ;
    rdf:predicate skos:member ;
    rdf:object eg:Pluto .
  ] .
 

The response confirms the removal.

HTTP/1.1 200 OK 
ETag: W/"1234567891"

eg:planets a skos:Collection, bp:Container;
   skos:prefLabel "The planets"@en;
   skos:member eg:Mercury;
   skos:member eg:Venus;
   skos:member eg:Earth;
   skos:member eg:Mars;
   skos:member eg:Jupiter;
   skos:member eg:Saturn;
   skos:member eg:Uranus;
   skos:member eg:Neptune.
 

3.19 Move a LDPC under another LDPC (UC-LDPC4-S4)

This example is based on The SKOS Primer. Assume we already have the following SKOS concepts. In this example, the concepts mammals, animals and cats are all defined as containers.

@prefix concept : <http://example.com/concept/>.

concept:animals a skos:Concept, bp:Container ;
   bp:membershipPredicate skos:narrower .
   
concept:mammals a skos:Concept, bp:Container ;
   bp:membershipPredicate skos:narrower ;
   skos:narrower concept:cats .

concept:cats a skos:Concept, bp:Container ;
   bp:membershipPredicate skos:narrower ;
   skos:broader concept:mammals .
   
 

We now wish to assert the concept hierarchy; the missing relationship between animals and mammals.

PATCH http://example.com/concept/animals HTTP/1.1
Host: example.com
Content-Type: text/turtle

@prefix : <http://example.com/>.
@prefix concept : <http://example.com/concept/>.

<change1>
  a cs:ChangeSet ;
  cs:subjectOfChange concept:animals ;
  cs:createdDate "2012-01-01T00:00:00Z" ;
  cs:changeReason "Update concept scheme" ;
  cs:addition [
    a rdf:Statement ;
    rdf:subject concept:animals ;
    rdf:predicate skos:narrower ;
    rdf:object concept:mammals .
  ] ;
  cs:addition [
    a rdf:Statement ;
    rdf:subject concept:mammals ;
    rdf:predicate skos:broader ;
    rdf:object concept:animals .
  ] ; 
 

The response confirms the addition.

HTTP/1.1 200 OK 
ETag: W/"1234567891"

@prefix concept : <http://example.com/concept/>.

concept:animals a skos:Concept, bp:Container ;
   bp:membershipPredicate skos:narrower ;
   skos:narrower concept:mammals.

concept:mammals skos:broader concept:animals .
 


3.20 Selective update (UC-LDPC5-S1)

Selectively add and remove properties to and from the identified resource. The scenario covers a typical sequence of events where the client first GETs the current state prior to the update.

  1. The client requests an HTTP GET of a URI identifying an LDP resource.
  2. The server answers with an RDF representation of the resource and the entity tag.
  3. The client requests an HTTP PATCH describing the updates.
  4. The server answers 204 No Content to confirm the patch.

This example relates to user-story Hosting posted resources, and is based on Helios.


GET http://example.com/mycatalog?non-member-properties HTTP/1.1
Host: example.com
Accept: text/turtle
 
HTTP/1.1 200 OK 
Content-Type: text/turtle
ETag: W/"9999999999"

@prefix : <http://example.com/dcat/>.

 :mycatalog a bp:Container;
   bp:membershipSubject :catalog;
   bp:membershipPredicate dcat:record.

 :catalog a dcat:Catalog ;
    dcterms:title "Example catalog" .
 

The new publisher information is added to the catalog with HTTP PATCH. This example uses a Talis changeset.

PATCH http://example.com/mycatalog?non-member-properties HTTP/1.1
Host: example.com
Content-Type: text/turtle
If-Match: W/"9999999999"

@prefix : <http://example.com/>.

<change1>
  a cs:ChangeSet ;
  cs:subjectOfChange :catalog ;
  cs:createdDate "2012-01-01T00:00:00Z" ;
  cs:changeReason "Update catalog metadata" ;
  cs:addition [
    a rdf:Statement ;
    rdf:subject : catalog ;
    rdf:predicate dcterms:publisher ;
    rdf:object <http://example.com/people/alice> .
  ] .
 

The response confirms successful update of the container resource.

HTTP/1.1 200 OK 
ETag: W/"10000000000"

@prefix : <http://example.com/>.

 :mycatalog a bp:Container;
   bp:membershipSubject :catalog;
   bp:membershipPredicate dcat:record.

 :catalog a dcat:Catalog ;
    dcterms:title "Example catalog" ;
    dcterms:publisher <http://example.com/people/alice>.
 

3.21 substituting update

  1. The client requests an HTTP GET of a URI identifying an LDP container non-membership properties.
  2. The server answers with an RDF representation of the container and the entity tag.
  3. The client requests an HTTP PUT with a replacement description and the appropriate Content-Type.
  4. The server answers 204 No Content to confirm the patch.

This example relates to user-story Hosting posted resources, and is based on Helios.

@prefix : <http://example.com/>.

 :mycatalog a bp:Container;
   bp:membershipSubject :catalog;
   bp:membershipPredicate dcat:record.

 :catalog a dcat:Catalog ;
    dcterms:title "Example catalog" ;
    dcat:record :record-001.
	   
 :record-001 a dcat:CatalogRecord ;
    foaf:primaryTopic :dataset-001 ;
    dcterms:issued "2011-12-11"^^xsd:date.
	   
 :dataset-001 a dcat:Dataset ;
    dcterms:title "Example dataset" .
 

The initial state of the non-membership properties of a container are retrieved.

GET http://example.com/mycatalog?non-member-properties HTTP/1.1
Host: example.com
Accept: text/turtle
 
HTTP/1.1 200 OK 
Content-Type: text/turtle
ETag: W/"9999999999"

@prefix : <http://example.com/dcat/>.

 :mycatalog a bp:Container;
   bp:membershipSubject :catalog;
   bp:membershipPredicate dcat:record.

 :catalog a dcat:Catalog ;
    dcterms:title "Example catalog" .
 

The non-membership properties of a container may be substituted with HTTP PUT.This enables us to add a publisher to the catalog.

PUT http://example.com/people/alice HTTP/1.1
Host: example.com
Content-Type: text/turtle
If-Match: W/"9999999999"

@prefix : <http://example.com/dcat/>.

 :mycatalog a bp:Container;
   bp:membershipSubject :catalog;
   bp:membershipPredicate dcat:record.

 :catalog a dcat:Catalog ;
    dcterms:title "Example catalog" ;
    dcterms:publisher <http://example.com/people/alice>.
 

The response confirms successful update of the container resource.

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

3.22 Requirements

3.22.1 TBD: Which of these follow from the use-cases?

  1. Update resources, either RDF-based or not
  2. Use optimistic collision detection on updates
  3. Apply minimal constraints for creation and update
  4. Remove a resource, including any associations with a container
  5. Get members of a container
  6. Get just data about a container, without all the members
  7. Handle a large number of members of a container, breaking up representation into pages

3.22.2 TBD: Which of these follow from use-cases?

  1. Define a minimal set of RDF media-types/representations
  2. Define a limited number of literal value types
  3. Use standard vocabularies as appropriate
  4. Ensure clients are ready for resource format and type changes
  5. When getting members of a container, provide data about the members
  6. Allow pages to have order information for members, within a page and across all pages