Skip to content

How to Use Linked Data Platform APIs (LDP) in Apache Marmotta

Eric Jahn edited this page Feb 16, 2021 · 2 revisions

LDP in Apache Marmotta

Note: this document describes usage of LDP protocols in the HSLynk platform to flexibly store any information as self-describing RDF. *Description of LDP's Apache Marmotta implementation within HSLynk. (https://github.com/servinglynk/hslynk-open-source-docs/wiki/Apache-Marmotta-Deployment-Within-HSLynk) Overview of using RDF to store any type of human services information in HSLynk: https://github.com/servinglynk/hslynk-open-source-docs/wiki/Entity-Support-in-HSLynk

LDP essentially lets you RESTfully (standard web methods) perform Create/Read/Update/Delete (CRUD) methods on Linked Data, which is built on the RDF format. So it lets you keep and maintain a collection of Linked Data, on whatever topic you wish.

Apache Marmotta 3.4.0 supports LDP (Linked Data Platform) with the restriction that only supports a Basic Container (LDP-BC). LDP writes and reads RDF using HTTP methods (i.e. GET, POST, PUT, DELETE, etc). In addition, LDP supports resources (LDPR) that contain RDF (LDP-RS) or non-RDF resources (LDP-NR) such as binary sources.

The LDP functionalities live in Apache Marmotta under /ldp. So in order to make a request to LDP, you should use the following URL $MARMOTTA_URL/ldp. If you need more information, you can jump at the official documentation.

This tutorial will walk you through the functionalities that Apache Marmotta provides for LDP. Also, take a look at some examples provided by the W3C.

In this tutorial, you can copy and paste the data and commands, but you can download the data folder if you want.

We will use the Case Management ontology and Service Transactions ontology for the examples provided. Go ahead and take a look at the ontologies here.

$MARMOTTA_URL: The integration of Apache Marmotta with HSLynk is being done in https://devmarmotta.hslynk.com/marmotta/ for development purposes.

LDP Operations

Create

LDP-RS

LDP-RS is a resource that is represented as RDF only. In order to create a resource in Apache Marmotta, we could make a POST to the /ldp service.

Let's create a Case. Case is already defined in the Case Management vocabulary, so let's create an instance.

  • Data (case-management/case-management.ttl)
@prefix case-management: <https://raw.githubusercontent.com/hserv/entity-tracking/master/case-management-ontology/case-management.ttl> .
@prefix dct:  <http://purl.org/dc/terms/> .

<> a case-management:Case ;
    dct:title "Case"^^xsd:string . 
    dct:description "A collection of plans and actions to serve a client." .

Once defined the RDF data, we tell the service that the RDF we are trying to store has the format text/turtle, and later we suggest to LDP how to create the URI with the Slug header (in this example, Case)

 curl -iX POST \
      -H "Content-Type: text/turtle" \
      -H "Slug: Case" \
      --data @case-management/case-management.ttl https://devmarmotta.hslynk.com/marmotta/ldp

Note: If the format provided in the Content-Type header is not recognized, the resource will be stored as an LDP-NR.

The Slug header suggests LDP how to create the URI for the resource.

Congrats, we have successfully created our Case. Now, the Case case lives under the URI https://devmarmotta.hslynk.com/ldp/Case.

  • Result
HTTP/1.1 201 Created
Server: Apache Marmotta/3.4.0 (build 0)
ETag: W/"1533502251000"
Last-Modified: Sun, 05 Aug 2018 20:50:51 GMT
Link: <http://wiki.apache.org/marmotta/LDPImplementationReport/2014-09-16>; rel="http://www.w3.org/ns/ldp#constrainedBy"
Link: <http://www.w3.org/ns/ldp#Resource>; rel="type"
Link: <http://www.w3.org/ns/ldp#RDFSource>; rel="type"
Link: <http://www.w3.org/ns/ldp#Container>; rel="type"
Link: <http://www.w3.org/ns/ldp#BasicContainer>; rel="type"
Location: https://devmarmotta.hslynk.com/ldp/Case
Content-Length: 0
Date: Sun, 05 Aug 2018 20:50:51 GMT

LDP-NR

LDP-NR are those resources that are not RDF. These data can vary from binary data to images or text files.

So, we can store not only RDF in Apache Marmotta. So let's add a client document image to our Case.

  • Data (case-management/ed-smith-utility_bill.png)

As before, we specify the file format and suggest a name for URI (ed-smith-utility-bill).

curl -iX POST -H "Content-Type: image/png" \
     -H "Slug: Ed Smith's proof of residence" \
     --data-binary @case-management/ed-utility-bill.png https://devmarmotta.hslynk.com/ldp/Case

That's all, we have added our utility bill image to the LDP container.

  • Result
HTTP/1.1 100 Continue

HTTP/1.1 201 Created
Server: Apache Marmotta/3.4.0 (build 0)
ETag: W/"1533503038000"
Last-Modified: Sun, 05 Aug 2018 21:03:58 GMT
Link: <http://wiki.apache.org/marmotta/LDPImplementationReport/2014-09-16>; rel="http://www.w3.org/ns/ldp#constrainedBy"
Link: <http://www.w3.org/ns/ldp#Resource>; rel="type"
Link: <http://www.w3.org/ns/ldp#RDFSource>; rel="type"
Link: <http://www.w3.org/ns/ldp#Container>; rel="type"
Link: <http://www.w3.org/ns/ldp#BasicContainer>; rel="type"
Link: <https://devmarmotta.hslynk.com/ldp/Case/ed-smith-utility-bill>; rel="describedby"; anchor="https://devmarmotta.hslynk.com/ldp/Case/ed-smith-utility-bill.png"
Location: https://devmarmotta.hslynk.com/ldp/Case/ed-smith-utility-bill.png
Content-Length: 0
Date: Sun, 05 Aug 2018 21:03:58 GMT

Interaction Model

By default, LDP creates a container (LDPC) that accepts (POST) new resources. However, you can create a resource LDPR (default for LDP-NR) if you don’t want to accept new resources. To do so, you can specify the type while creating resources, just add a Link header while creating.

 -H 'Link: <http://www.w3.org/ns/ldp#Resource>; rel="type"'

Read

For reading the content of a resource, you can make a HTTP GET to the resource you are looking for.

Let's read our Case resource.

curl -i -H "Accept: text/turtle" https://devmarmotta.hslynk.com/ldp/Case

Note: You need to provide a supported format in the Accept header.

  • Result
HTTP/1.1 200 OK
Server: Apache Marmotta/3.4.0 (build 0)
Accept-Patch: application/rdf-patch
Accept-Post: text/turtle, application/ld+json, application/rdf+xml, text/n3, */*
Allow: HEAD, DELETE, POST, GET, OPTIONS, PUT, PATCH
ETag: W/"1533503038000"
Last-Modified: Sun, 05 Aug 2018 21:03:58 GMT
Link: <http://wiki.apache.org/marmotta/LDPImplementationReport/2014-09-16>; rel="http://www.w3.org/ns/ldp#constrainedBy"
Link: <http://www.w3.org/ns/ldp#Resource>; rel="type"
Link: <http://www.w3.org/ns/ldp#RDFSource>; rel="type"
Link: <http://www.w3.org/ns/ldp#Container>; rel="type"
Link: <http://www.w3.org/ns/ldp#BasicContainer>; rel="type"
Content-Type: text/turtle
Transfer-Encoding: chunked
Date: Sun, 05 Aug 2018 21:08:32 GMT

@prefix ldp: <http://www.w3.org/ns/ldp#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix dcterms: <http://purl.org/dc/terms/> .
@prefix parent: <https://devmarmotta.hslynk.com/ldp/> .
@prefix child: <https://devmarmotta.hslynk.com/ldp/Case/> .
@prefix this: <https://devmarmotta.hslynk.com/ldp/Case#> .

parent:Case a ldp:Resource , ldp:RDFSource , ldp:Container , ldp:BasicContainer ;
	ldp:interactionModel ldp:Container ;
	dcterms:created "2018-08-05T15:50:51.000-05:00"^^xsd:dateTime ;
	dcterms:modified "2018-08-05T16:03:58.000-05:00"^^xsd:dateTime ;
	ldp:contains child:ed-smith-utility-bill.png ;
	a <https://raw.githubusercontent.com/hserv/entity-tracking/master/case-management-ontology/case-management.ttl#Case> ;
	dcterms:title "Case."^^xsd:string ;
        dct:description "A collection of plans and actions to serve a client." .

Wait a moment... That is a lot of information! Why did LDP return ldp types in the RDF (information of the container)? By default, when reading, LDP returns all data, but you can retrieve only the content of the resource by providing the Prefer header.

So, now let's only retrieve the information that we need:

curl -i -H "Accept: text/turtle" \
     -H 'Prefer: return=representation; omit="http://www.w3.org/ns/ldp#PreferMinimalContainer http://www.w3.org/ns/ldp#PreferContainment"' \
     https://devmarmotta.hslynk.com/ldp/Case
  • Result
HTTP/1.1 200 OK
Server: Apache Marmotta/3.4.0 (build 0)
Accept-Patch: application/rdf-patch
Accept-Post: text/turtle, application/ld+json, application/rdf+xml, text/n3, */*
Allow: HEAD, DELETE, POST, GET, OPTIONS, PUT, PATCH
ETag: W/"1533503038000"
Last-Modified: Sun, 05 Aug 2018 21:03:58 GMT
Link: <http://wiki.apache.org/marmotta/LDPImplementationReport/2014-09-16>; rel="http://www.w3.org/ns/ldp#constrainedBy"
Link: <http://www.w3.org/ns/ldp#Resource>; rel="type"
Link: <http://www.w3.org/ns/ldp#RDFSource>; rel="type"
Link: <http://www.w3.org/ns/ldp#Container>; rel="type"
Link: <http://www.w3.org/ns/ldp#BasicContainer>; rel="type"
Preference-Applied: return="representation"
Content-Type: text/turtle
Transfer-Encoding: chunked
Date: Sun, 05 Aug 2018 21:11:03 GMT

@prefix ldp: <http://www.w3.org/ns/ldp#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix dcterms: <http://purl.org/dc/terms/> .
@prefix parent: <https://devmarmotta.hslynk.com/ldp/> .
@prefix child: <https://devmarmotta.hslynk.com/ldp/Case/> .
@prefix this: <https://devmarmotta.hslynk.com/ldp/Case#> .

parent:Case a <https://raw.githubusercontent.com/hserv/entity-tracking/master/case-management-ontology/case-management.ttl#Case> ;
    dcterms:title "Case."^^xsd:string .
    dct:description "A collection of plans and actions to serve a client." .

That is exactly what we were looking for, but I want also to see what content our utility bill image has. Easy, we can also read non-RDF resources (LDP-NR) in the same way. For example:

curl -I https://devmarmotta.hslynk.com/ldp/Case/ed-smith-utility-bill.png
  • Result
HTTP/1.1 200 OK
Server: Apache Marmotta/3.4.0 (build 0)
Allow: HEAD, DELETE, GET, OPTIONS, PUT
ETag: "8b1bb6bcbe1a8b1dcb2e9e111cc0f7a8"
Last-Modified: Sun, 05 Aug 2018 21:03:58 GMT
Link: <http://wiki.apache.org/marmotta/LDPImplementationReport/2014-09-16>; rel="http://www.w3.org/ns/ldp#constrainedBy"
Link: <http://www.w3.org/ns/ldp#Resource>; rel="type"
Link: <http://www.w3.org/ns/ldp#NonRDFSource>; rel="type"
Link: <https://devmarmotta.hslynk.com/ldp/Case/ed-smith-utility-bill>; rel="describedby"
Link: <https://devmarmotta.hslynk.com/ldp/Case/ed-smith-utility-bill>; rel="meta"
Content-Type: image/png
Content-Length: 0
Date: Sun, 05 Aug 2018 21:13:17 GMT

As expected, we can see that our utility bill image has a non resource (LDR-NR) type. It also has a content-length zero since we didn't store any RDF.

Additionally, if we take a look to our Case again, we can see that LDP added a ldp:contains property to our utility bill image. This is because Marmotta cross-references an LDP-NR with its associated LDP-RS using meta and content links.

curl -i -H "Accept: text/turtle" https://devmarmotta.hslynk.com/ldp/Case
  • Result
HTTP/1.1 200 OK
Server: Apache Marmotta/3.4.0 (build 0)
Accept-Patch: application/rdf-patch
Accept-Post: text/turtle, application/ld+json, application/rdf+xml, text/n3, */*
Allow: HEAD, DELETE, POST, GET, OPTIONS, PUT, PATCH
ETag: W/"1533503038000"
Last-Modified: Sun, 05 Aug 2018 21:03:58 GMT
Link: <http://wiki.apache.org/marmotta/LDPImplementationReport/2014-09-16>; rel="http://www.w3.org/ns/ldp#constrainedBy"
Link: <http://www.w3.org/ns/ldp#Resource>; rel="type"
Link: <http://www.w3.org/ns/ldp#RDFSource>; rel="type"
Link: <http://www.w3.org/ns/ldp#Container>; rel="type"
Link: <http://www.w3.org/ns/ldp#BasicContainer>; rel="type"
Content-Type: text/turtle
Transfer-Encoding: chunked
Date: Sun, 05 Aug 2018 21:23:18 GMT

@prefix ldp: <http://www.w3.org/ns/ldp#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix dcterms: <http://purl.org/dc/terms/> .
@prefix parent: <https://devmarmotta.hslynk.com/ldp/> .
@prefix child: <https://devmarmotta.hslynk.com/ldp/Case/> .
@prefix this: <https://devmarmotta.hslynk.com/ldp/Case#> .

parent:Case a ldp:Resource , ldp:RDFSource , ldp:Container , ldp:BasicContainer ;
	ldp:interactionModel ldp:Container ;
	dcterms:created "2018-08-05T15:50:51.000-05:00"^^xsd:dateTime ;
	dcterms:modified "2018-08-05T16:03:58.000-05:00"^^xsd:dateTime ;
	ldp:contains child:ed-smith-utility-bill.png ;
	a <https://raw.githubusercontent.com/hserv/entity-tracking/master/case-management-ontology/case-management.ttl#Case> ;
	dcterms:title "Case."^^xsd:string .
        dct:description "A collection of plans and actions to serve a client." .

Update

In order to update a resource, we need the ETag number of a resource. The ETag number is returned in the headers while reading or inserting a resource (go ahead and look for the Etag header in the above results). We use the ETag number with the If-Match header to update our resource.

So now, let's add our utility bill to the case. To do so, we are going to use the foaf:depiction property.

  • Data (case-management/case_with_utility_bill.ttl)
@prefix case-management: <https://raw.githubusercontent.com/hserv/entity-tracking/master/case-management-ontology/case-management.ttl#> .
@prefix dct:  <http://purl.org/dc/terms/> .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .

<> a case-management:Case ;
    foaf:depiction <Case/ed-smith-utility-bill.png>;
    dct:title "Housing case for Ed Smith."^^xsd:string .

After doing a HTTP GET to our Case, we see that our ETag is the number 1533503038000. So, we update our case using the header If-Match.

curl -iX PUT -H "Content-Type: text/turtle" \
     -H 'If-Match: W/"1533503038000"' \
     -d @case-management/case_with_ed-smith-utility-bill.ttl https://devmarmotta.hslynk.com/ldp/Case
  • Result
HTTP/1.1 200 OK
Server: Apache Marmotta/3.4.0 (build 0)
ETag: W/"1533505007000"
Last-Modified: Sun, 05 Aug 2018 21:36:47 GMT
Link: <http://wiki.apache.org/marmotta/LDPImplementationReport/2014-09-16>; rel="http://www.w3.org/ns/ldp#constrainedBy"
Link: <http://www.w3.org/ns/ldp#Resource>; rel="type"
Link: <http://www.w3.org/ns/ldp#RDFSource>; rel="type"
Link: <http://www.w3.org/ns/ldp#Container>; rel="type"
Link: <http://www.w3.org/ns/ldp#BasicContainer>; rel="type"
Content-Length: 0
Date: Sun, 05 Aug 2018 21:36:47 GMT

If we see our Case (see read section), we see that our utility bill image has being added using foaf ontology.

@prefix ldp: <http://www.w3.org/ns/ldp#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix dcterms: <http://purl.org/dc/terms/> .
@prefix parent: <https://devmarmotta.hslynk.com/ldp/> .
@prefix child: <https://devmarmotta.hslynk.com/ldp/Case/> .
@prefix this: <https://devmarmotta.hslynk.com/ldp/Case#> .

parent:Case a ldp:Resource , ldp:RDFSource , ldp:Container , ldp:BasicContainer ;
	ldp:interactionModel ldp:Container ;
	dcterms:created "2018-08-05T15:50:51.000-05:00"^^xsd:dateTime ;
	dcterms:modified "2018-08-05T16:36:47.000-05:00"^^xsd:dateTime ;
	ldp:contains child:ed-smith-utility-bill.png ;
	a <https://raw.githubusercontent.com/hserv/entity-tracking/master/case-management-ontology/case-management.ttl#Case> ;
	<http://xmlns.com/foaf/0.1/depiction> child:ed-smith-utility-bill.png ;
	dcterms:title "Housing case for Ed Smith."^^xsd:string .

Delete

In order to delete a container, we just need the container identifier (URI) which might be constructed with the Slug header (see the Create section).

curl -iX DELETE https://devmarmotta.hslynk.com/ldp/Case
  • Result
HTTP/1.1 204 No Content
Server: Apache Marmotta/3.4.0 (build 0)
Link: <http://wiki.apache.org/marmotta/LDPImplementationReport/2014-09-16>; rel="http://www.w3.org/ns/ldp#constrainedBy"
Date: Wed, 25 Jul 2018 04:13:21 GMT

This operation will delete all data from the container and mark it as ‘used’, so future requests will respond with the HTTP 410 Gone header.

HTTP/1.1 410 Gone
Server: Apache Marmotta/3.4.0 (build 0)
Link: <http://wiki.apache.org/marmotta/LDPImplementationReport/2014-09-16>; rel="http://www.w3.org/ns/ldp#constrainedBy"
Content-Length: 0
Date: Wed, 25 Jul 2018 04:15:04 GMT

Head

The head method can be used in order to obtain basic information from the container such as supported HTTP methods, Etag header, and accepted mime types. This information is also returned in the GET requests.

curl --head HEAD https://devmarmotta.hslynk.com/ldp/Case
  • Result
HTTP/1.1 200 OK
Server: Apache Marmotta/3.4.0 (build 0)
Accept-Patch: application/rdf-patch
Accept-Post: text/turtle, application/ld+json, application/rdf+xml, text/n3, */*
Allow: HEAD, DELETE, POST, GET, OPTIONS, PUT, PATCH
ETag: W/"1533505007000"
Last-Modified: Sun, 05 Aug 2018 21:36:47 GMT
Link: <http://wiki.apache.org/marmotta/LDPImplementationReport/2014-09-16>; rel="http://www.w3.org/ns/ldp#constrainedBy"
Link: <http://www.w3.org/ns/ldp#Resource>; rel="type"
Link: <http://www.w3.org/ns/ldp#RDFSource>; rel="type"
Link: <http://www.w3.org/ns/ldp#Container>; rel="type"
Link: <http://www.w3.org/ns/ldp#BasicContainer>; rel="type"
Content-Type: text/turtle
Content-Length: 0
Date: Sun, 05 Aug 2018 21:51:08 GMT

PATCH

PATCH is another alternative that can be used to update a resource. It follows the same strategy that the PUT method, using the Etag and If-Match headers, but PATCH submits an RDF-patch instead of an RDF file. In other words, PATCH allows to add or remove triples without the need to resend all the triples. This means that the information sent within the requests correspond only to adding/deleting operations rather than a complete RDF file with modifications.

PATCH requires the header Accept-Patch in order to define the format file to be used in the request. Currently, Apache Marmotta only supports RDF-patch (MIME Type: application/rdf-patch). A complete description of this file format, its syntaxis and features can be accessed on the working draft of its specification.

Back to our example, let's suppose we want to replace the title of our Case. This action can be split into two RDF-patch operations. Delete the old title triple and add a new one with the correct title. So, in the file case_edit.rdfp, we delete (D) the triple with the title Housing case for Ed Smith., and add the triple with the title Housing case for Ed Smith. This is some more text added to the title..

  • Data (case-management/case_edit.rdfp)
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix case-management: <https://raw.githubusercontent.com/hserv/entity-tracking/master/case-management-ontology/case-management.ttl#> .
@prefix dct:  <http://purl.org/dc/terms/> .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .

D <https://devmarmotta.hslynk.com/ldp/Case> dct:title "Housing case for Ed Smith."^^xsd:string .
A <https://devmarmotta.hslynk.com/ldp/Case> dct:title "Housing case for Ed Smith. This is some more text added to the title."^^xsd:string .

And to update the title triple in the Marmotta triplestore, we just have to look for the ETag (e.g. ETag = 1534114207000) number and send a PATCH request as follows:

curl -iX PATCH -H "Content-Type: application/rdf-patch" \                                         
     -H 'If-Match: W/"1534114207000"' \
     -d @case-management/case_edit.rdfp https://devmarmotta.hslynk.com/ldp/Case

And that's all, we have updated our Case case title, and we will get a response as follows:

  • Result
HTTP/1.1 204 No Content
Server: Apache Marmotta/3.4.0 (build 0)
ETag: W/"1534114802000"
Last-Modified: Sun, 12 Aug 2018 23:00:02 GMT
Link: <http://wiki.apache.org/marmotta/LDPImplementationReport/2014-09-16>; rel="http://www.w3.org/ns/ldp#constrainedBy"
Link: <http://www.w3.org/ns/ldp#Resource>; rel="type"
Link: <http://www.w3.org/ns/ldp#RDFSource>; rel="type"
Link: <http://www.w3.org/ns/ldp#Container>; rel="type"
Link: <http://www.w3.org/ns/ldp#BasicContainer>; rel="type"
Date: Sun, 12 Aug 2018 23:00:11 GMT

Notice that due the Marmotta's implementation of RDF-patch it is not possible to use the diamond operator <>, it is mandatory to use the complete URI of the resources.

Using the Case Management Ontology

Okay, we have created a Case using our Case Management Ontology, but wait a minute we can have goals, plans, or milestones. So let's start by setting a goal for our case now that we are experts on LDP.

curl -iX POST \
      -H "Content-Type: text/turtle" \
      -H "Slug: Skills" \
      --data @case-management/goal.ttl https://devmarmotta.hslynk.com/ldp/Case
  • Data (case-management/goal.ttl)
@prefix case-management: <https://raw.githubusercontent.com/hserv/entity-tracking/master/case-management-ontology/case-management.ttl#> .
@prefix dct:  <http://purl.org/dc/terms/> .

<> a case-management:Goal ;
    dct:title "Hire people with Case Management skills."^^xsd:string .

Great! We can continue by adding a plan to our goal.

curl -iX POST \
      -H "Content-Type: text/turtle" \
      -H "Slug: Plan" \
      --data @case-management/plan.ttl https://devmarmotta.hslynk.com/ldp/Case/Skills
  • Data (case-management/plan.ttl)
@prefix case-management: <https://raw.githubusercontent.com/hserv/entity-tracking/master/case-management-ontology/case-management.ttl#> .
@prefix dct:  <http://purl.org/dc/terms/> .

<> a case-management:Plan ;
    dct:title "Organize meetings to interview aspirants."^^xsd:string .

Finally, we will add a milestone to our plan.

curl -iX POST \
      -H "Content-Type: text/turtle" \
      -H "Slug: Milestone" \
      --data @case-management/milestone.ttl https://devmarmotta.hslynk.com/ldp/Case/Skills/Plan
  • Data (case-management/milestone.ttl)
@prefix case-management: <https://raw.githubusercontent.com/hserv/entity-tracking/master/case-management-ontology/case-management.ttl#> .
@prefix dct:  <http://purl.org/dc/terms/> .

<> a case-management:Milestone ;
    dct:title "Have eligibility determined."^^xsd:string .

Great, we have used our Case Management ontology sucessfully!

Using the Service Transactions Ontology

In order to continue with the LDP explanation, we are going to make use of the Service Transactions Ontology. Let’s first define our LDP containers.

In this tutorial we will create three containers based on the main classes of the ontology, however, in a real application scenario, the number, and granularity of the containers should be analyzed more consciously.

ServiceTransaction

This container handles the information of ServiceTransactions, referrals, services and siteServices. The base URI for this container is devinternal.hslynk.com:20901/ldp/serviceTransaction.

In order to create the container, we execute the following request.

curl -iX POST \
  	-H "Content-Type: text/turtle" \
  	-H "Slug: serviceTransaction" \
  	--data @service-transaction/baseServiceTransaction.ttl https://devmarmotta.hslynk.com/ldp
  • Data (service-transaction/baseServiceTransaction.ttl)
@prefix ldp: <http://www.w3.org/ns/ldp#> .
@prefix dcterms: <http://purl.org/dc/terms/> .
 
<> a ldp:Container, ldp:BasicContainer ;
	dcterms:title "Service Transations Container" ;
	dcterms:description "This container handles the information of ServiceTransactions, referrals, services and siteServices." .

This operation should return a 201 Created response meaning that the container was created successfully.

Now that the container is created we can our first ServiceTransaction record. That could be performed by adding a new resource to the container as follows:

curl -iX POST \
  	-H "Content-Type: text/turtle" \
  	-H "Slug: st1" \
     -H 'Link: <http://www.w3.org/ns/ldp#Resource>; rel="type"' \
  	--data @service-transaction/st1.ttl https://devmarmotta.hslynk.com/ldp/serviceTransaction
  • Data (service-transaction/st1.ttl):
@prefix service-transaction: <https://raw.githubusercontent.com/hserv/entity-tracking/master/service-transaction-ontology/service-transaction.ttl> .
@prefix airs: <https://raw.githubusercontent.com/airsalliance/lov/master/src/airs_vocabulary.ttl#> .
 
<> a service-transaction:ServiceTransaction ;
service-transaction:dateProvided "2004-04-12T13:20:00-05:00"^^xsd:dateTimeStamp ;
service-transaction:created "2005-04-12T13:20:00-05:00"^^xsd:dateTimeStamp ;
service-transaction:dataCollectionStage "Stage A"^^xsd:string ;
service-transaction:userID "U001"^^xsd:string ;
service-transaction:providedBy airs:ExtSiteService .
 
airs:ExtSiteService a airs:SiteService.

This operation should return a 201 Created response.

Now let’s add a new ServiceTransaction record, but this time the record has a referral relationship within its information; let's call it st2. The content of this record is the following:

  • Data (service-transaction/st2.ttl)
@prefix service-transaction: <https://raw.githubusercontent.com/hserv/entity-tracking/master/service-transaction-ontology/service-transaction.ttl> .
@prefix airs: <https://raw.githubusercontent.com/airsalliance/lov/master/src/airs_vocabulary.ttl#> .
 
<> a service-transaction:ServiceTransaction ;
   service-transaction:dateProvided "2004-08-12T13:20:00-05:00"^^xsd:dateTimeStamp ;
   service-transaction:created "2007-09-12T13:20:00-05:00"^^xsd:dateTimeStamp ;
   service-transaction:dataCollectionStage "Stage C"^^xsd:string ;
   service-transaction:userID "U002"^^xsd:string ;
   service-transaction:hasReferral service-transaction:referra01 .
 
   service-transaction:referra01 a service-transaction:Referral ;
   service-transaction:dataCollectionStage "Stage B"^^xsd:string ;
   service-transaction:referredTo airs:service01;
   service-transaction:referredTo airs:siteService01 .
 
   airs:siteService01 a airs:SiteService .
   airs:service01 a airs:Service .

But wait a minute we forgot about Taxonomies, they are part of the information of a ServiceTransaction. No panic, we can create some resources for taxonomies on its container and then edit our ServiceTransaction records in order to add proper relations.

TaxonomyClass

The creation process of a container for taxonomies is similar to what we have done before, except that the container will have the following base URI devinternal.hslynk.com:20901/ldp/taxonomyClassification.

curl -iX POST \
  	-H "Content-Type: text/turtle" \
  	-H "Slug: taxonomyClassification" \
  	--data @service-transaction/base_taxonomy.ttl https://devmarmotta.hslynk.com/ldp
  • Data (service-transaction/base_taxomomy.ttl)
@prefix ldp: <http://www.w3.org/ns/ldp#> .
@prefix dcterms: <http://purl.org/dc/terms/> .
 
<> a ldp:Container, ldp:BasicContainer ;
	dcterms:title "Taxomonies Container" ;
	dcterms:description "This container handles the information of taxonomies." .

Let’s create a couple of instances for the new container.

curl -iX POST \
  	-H "Content-Type: text/turtle" \
  	-H "Slug: t1" \
     -H 'Link: <http://www.w3.org/ns/ldp#Resource>; rel="type"' \
  	--data @service-transaction/st1.ttl https://devmarmotta.hslynk.com/ldp/ taxonomyClassification
  • Data (service-transaction/t1.ttl)
@prefix service-transaction: <https://raw.githubusercontent.com/hserv/entity-tracking/master/service-transaction-ontology/service-transaction.ttl> .
@prefix airs: <https://raw.githubusercontent.com/airsalliance/lov/master/src/airs_vocabulary.ttl#> .
 
<> a airs:TaxonomyClassification;
   airs:taxonomyValue "Value 1"^^xsd:string ;
   airs:hasTaxonomyName service-transaction:airs .
 
   airs:airs a airs:TaxonomyName .
  • Data (service-transaction/t2.ttl)
@prefix service-transaction: <https://raw.githubusercontent.com/hserv/entity-tracking/master/service-transaction-ontology/service-transaction.ttl> .
@prefix airs: <https://raw.githubusercontent.com/airsalliance/lov/master/src/airs_vocabulary.ttl#> .
 
<> a service-transaction:TaxonomyClassification;
   service-transaction:taxonomyValue "Value 2"^^xsd:string ;
   airs:hasTaxonomyName airs:open_eligibility .
 
   airs:open_eligibility a airs:TaxonomyName .

Back to the ServiceTransaction container, we have to add a taxonomy to our instances. In order to modify the resources, we can use a PATCH requests. Let’s begin by completing the information of our first ServiceTransaction (https://devmarmotta.hslynk.com/ldp/serviceTransaction/st1). But first, we need to know its Etag value in order to execute the PATCH. To obtain that value we can simply run an HTTP HEAD on the URI which should give us a response similar to this.

Accept-Patch:  application/rdf-patch
Allow:  PATCH, GET, DELETE, OPTIONS, PUT, HEAD
Cache-Control:  private
Content-Length:  0
Content-Type:  text/turtle
Date:  Mon, 13 Aug 2018 18:00:21 GMT
ETag:  W/"1534178607000"
Expires:  Wed, 31 Dec 1969 19:00:00 ECT
Last-Modified:  Mon, 13 Aug 2018 16:43:27 GMT
Link:  <http://wiki.apache.org/marmotta/LDPImplementationReport/2014-09-16>; rel="http://www.w3.org/ns/ldp#constrainedBy", <http://www.w3.org/ns/ldp#Resource>; rel="type", <http://www.w3.org/ns/ldp#RDFSource>; rel="type"
Server:  Apache Marmotta/3.4.0 (build 0)

Now we know the Etag and we can proceed to add a new relation between the ServiceTransaction and TaxonomyClassification.

curl -iX PATCH -H "Content-Type: application/rdf-patch" \                                     	
 	-H 'If-Match: W/"1534178607000"' \
 	-d @service-transaction/addTaxonomy.rdfp https://devmarmotta.hslynk.com/ldp/serviceTransaction/st1
  • Data (service-transaction/addTaxonomy.rdfp)
@prefix service-transaction: <https://raw.githubusercontent.com/hserv/entity-tracking/master/service-transaction-ontology/service-transaction.ttl> .
 
A <https://devmarmotta.hslynk.com/ldp/serviceTransaction/st1> service-transaction:hasTaxonomyClassification <https://devmarmotta.hslynk.com/ldp/taxonomyClassification/t1>

NeedIdentification

Finally, we can create instances for our final container NeedIdentification. The base URI defined for this container is ‘devinternal.hslynk.com:20901/ldp/NeedIdentification’. And we can create the LDP container repeating the POST request described before with the next turtle file.

  • Data (service-transaction/needindentification.ttl)
@prefix ldp: <http://www.w3.org/ns/ldp#> .
@prefix dcterms: <http://purl.org/dc/terms/> .
 
<> a ldp:Container, ldp:BasicContainer ;
	dcterms:title "NeedIdentification Container" ;
	dcterms:description "This container handles the information of NeedIdentifications."

With the container ready we should proceed to populate it with an instance. To do so, we can POST the next turtle file to the container in a similar way to the containers described above.

  • Data (service-transaction/needindentificationInfo.ttl)
@prefix service-transaction: <https://raw.githubusercontent.com/hserv/entity-tracking/master/service-transaction-ontology/service-transaction.ttl> .
@prefix airs: <https://raw.githubusercontent.com/airsalliance/lov/master/src/airs_vocabulary.ttl#> .
 
 
<> a service-transaction:NeedIdentification ;
   service-transaction:dataCollectionStage "Stage A"^^xsd:string ;
   service-transaction:userID "U001"^^xsd:string ;
   service-transaction:hasTaxonomyClassification <https://devmarmotta.hslynk.com/ldp/taxonomyClassification/t1> ;
   service-transaction:hasServiceTransaction <https://devmarmotta.hslynk.com/ldp/serviceTransaction/st1> ;
   service-transaction:hasNeedStatusValue service-transaction:in_progress .
 
   service-transaction:status_ni1 a service-transaction:NeedStatus ;
   service-transaction:dateEffective "03/03/2018"^^xsd:string ;
   service-transaction:userID "03/03/2018"^^xsd:string ;
   service-transaction:created "01/03/2018"^^xsd:string ;
   service-transaction:hasNeedStatusValue service-transaction:in_progress .

Wrapping up, we have divided the ServiceTransaction ontology into three LDP containers which can effectively handle the resources and instances of the ontology. Moreover, the operations required for creating the containers, populate them with resources and edit them if necessary are exemplified. As a final result of the implementation of this specific case, we have deployed the following LDP APIS.

Path Method Description
devinternal.hslynk.com:20901/ldp/ serviceTransaction/{ID} GET Obtain information related with a Service Transaction.
DELETE Delete a Service Transaction.
PATCH Update information of a Service Transaction.
POST Add a new Service Transaction record.
devinternal.hslynk.com:20901/ldp/ taxonomyClassification/{ID} GET Obtain information related with a Taxonomy Classification.
DELETE Delete a Taxonomy Classification.
PATCH Update information of a Taxonomy Classification.
POST Add a new Taxonomy Classification record.
devinternal.hslynk.com:20901/ldp/ NeedIdentification/{ID} GET Obtain information related with a NeedIdentification.
DELETE Delete a NeedIdentification.
PATCH Update information of a NeedIdentification.
POST Add a new NeedIdentification record.

Only the most used methods are showed, there are plenty more methods such HEAD, OPTIONS, PUT.