Linked Data Templates (LDT) is a uniform protocol for read-write Linked Data. This document defines an abstract syntax (a data model) of Linked Data applications with SPARQL backends, and semantics of CRUD interactions against their resources. [[LINKED-DATA]][[sparql11-overview]]

LDT can be used to design ontology-driven Web application programming interfaces (APIs). It provides facilities to define interactions with application resources declaratively using SPARQL commands. It also provides a standard method to evaluate requests into responses over application ontology and dataset.

Introduction

Linked Data is a method for publishing structured data, including relationships between data, on the Web using a common data model (RDF). The purpose of Linked Data Templates is to provide means to define read-write Linked Data APIs declaratively using SPARQL and specify a uniform interaction protocol for them.

LDT reconciles ontology-driven Semantic Web, read-write Linked Data and the SPARQL query language. LDT architecture decouples software from domain- or application-specific operations, enabling reuse of machine-processable operation descriptions (for composition, reasoning etc.) as well as generic implementations of both server and client software. It builds on existing standards; no changes or additions to other specifications are required.

Ontology as a declarative representation of the application's operations, dependency on SPARQL, formal valuation of interactions and the support for HATEOAS hypermedia are the main features that distinguish LDT from other Linked Data specifications such as Linked Data Platform [[LDP]]. Rather than prescribing a single interaction model as does LDP, LDT specifies ontology structure and processing rules that allow applications to define custom interaction models.

This document defines a precise semantics for SPARQL-backed Linked Data applications, providing a specification of how Append, Read, Update, Delete (CRUD) interactions change the state of their resources. It does so by establishing the following:

The main LDT concepts are explained below.

Applications

LDT architecture
Main components of LDT architecture

An LDT application represents a data space identified by its base URI, in which application resource URIs are usually (but not necessarily) relative to the base URI. The only interface an application provides is RESTful Linked Data: application produces RDF representations when resource URIs are dereferenced, and consumes RDF representations when requested to change resource state.

Services

A service is a datasource from which an LDT application retrieves, and in which it stores RDF data with resource representations. The only interface a service MUST provide is SPARQL 1.1 Protocol [[[sparql11-protocol]]]. That way an application is agnostic to the service implementation details: it can be a native RDF triplestore, an RDBMS or XML database with an RDF wrapper, or any other compliant datasource.

Ontologies

An ontology is an efficient way to define application structure declaratively as a set of instructions for resource representation processing. LDT application uses a single RDF ontology to define operations specific to that application. Ontologies can be exposed and dereferenced, as well as imported and reused by other LDT applications or third-party software.

Operations

An operation maps a certain URI pattern to a certain SPARQL command. During request processing, an LDT processor matches request URI against operations and selects the best match (if such exists) that will drive the RDF CRUD processing. Operations are defined using the LDT vocabulary, while the SPARQL commands are defined using SPIN RDF syntax and use a "magic" variable ?this which is bound to the request URI value.

Processes such as content negotiation, URI resolution, constraint validation etc. are separate from operations and out of scope of this document.

Hypermedia

Hypermedia, used here in terms of Hypermedia As The Engine Of Application State (HATEOAS), is the final constraint of REST. It enables loose server/client coupling by requiring the client to navigate by transitioning between server-provided application states. It implies that those states need to be URI-identified and provided in response body. LDT addresses this by providing operation parameters that are used to validate and describe requested application states.

Abstract syntax

This section defines the data model of LDT applications.

REST

In this section we define the abstract syntax REpresentational State Transfer. It sufficient to model a RESTful API independently of the transport protocol.

Request
Request
Response
Response
Body
Message-body
MediaType
Media-type
Status
Status
IRI
IRI
Method
Interaction-method

Request := Method IRI | Method IRI MediaType Body
Response := Status MediaType Body

Linked Data

In this section, we specialize the REST abstract syntax by constraining the message body to RDF serializations and read-write interactions to CRUD.

LDRequest
RDF-request ⊂ Request
LDResponse
RDF-response ⊂ Response
RDFMediaType
RDF-media-type ⊂ Media-type
Dataset
Dataset ⊂ Body
CRUDMethod
CRUD-method ⊂ Method
CRUDStatus
CRUD-status ⊂ Status

LDRequest := CRUDMethod IRI | CRUDMethod IRI RDFMediaType Dataset
LDResponse := CRUDStatus RDFMediaType Dataset
CRUDMethod := Append | Read | Delete | Update
CRUDStatus := NotFound | NoContent | OK

Semantics

We use denotational semantics as the formalism for Linked Data semantics.

Domains

Method
Interaction method [[webarch]]
IRIabs
non-relative IRI identifier [[!rdf11-concepts]]
MediaType
Media Type [[!rfc2046]]
Body
Representation [[!webarch]]
Request
Method × IRIabs × MediaType × Body
RDFMediaType
{ text/turtle, text/trig, application/n-triples, application/n-quads, application/ld+json, application/rdf+xml, … } Writing RDF graphs [[rdf11-primer]]
CRUDMethod
{ Append, Read, Delete, Update }
CRUDStatus
{ NotFound, NoContent, OK }
Dataset
RDF dataset [[!rdf11-concepts]][[!sparql11-query]]
LDRequest
CRUDMethod × IRIabs × RDFMediaType × Dataset
LDResponse
CRUDStatus × RDFMediaType × Dataset
Ontology
Operation* × Ontology*
Denotational semantics do not allow recursive domain definitions such as the one above. This would need to be reworked to be strictly formal.
App
IRI × Ontology × Dataset
Here we define an ontology with a Dataset, yet the implementation/vocabulary uses a Service which is an interface for the Dataset.
QueryVariable
Query Variable [[!sparql11-query]]
RDFTerm
RDF Term [[!sparql11-query]]
QueryBinding
QueryVariable × RDFTerm
Describe
DESCRIBE [[!sparql11-query]]
Construct
CONSTRUCT [[!sparql11-query]]
Query
Describe + Construct
Delete
DELETE [[!sparql11-update]]
Command
Query + Delete
IRIPattern
URI template [[!JAX-RS]]
Parameter
String × IRI × Boolean
Operation
IRIPattern × Query × Delete × Parameter*
OperationPrecedence
Operation × Integer
Argument
Parameter × RDFTerm

Functions

absolutePath
IRIIRIabs
absolutePath(iri) = fn:substring-before(absoluteIri, "?") = absolutePath ∈ IRIabs [[!xpath-functions-31]]
queryString
IRI → String
queryString(iri) = fn:substring-after(absoluteIri, "?") = queryString ∈ String [[!xpath-functions-31]]
method
Request↓1 → Method
iri
Request↓2 → IRI
mediaType
Request↓3 → MediaType + { NoType }
body
Request↓4 → Body
operations
Ontology↓1 → Operation*
imports
Ontology↓2 → Ontology*
base
App↓1 → IRI
ontology
App↓2 → Ontology
dataset
App↓3 → Dataset
relativize
IRI × IRIIRIrelIRI
relativize(absoluteIri1, absoluteIri2) = relativeIri
The processor MUST implement relativize as defined in Relative Resolution [[!rfc3986]].
app
IRIApp
app(iri) = appminPath ∈ App such that
fn:string-length(relativize(base(appminPath), iri)) ≤ fn:string-length(relativize(base(app), iri))
for all app ∈ App : app ≠ appminPath [[xpath-functions-31]]
apply
Command × QueryBinding* → Command
execQuery
Query × DatasetDataset
execDelete
Delete × DatasetDataset
empty
Dataset
Empty RDF dataset [[!sparql11-update]]
name
Parameter↓1 → String
valueType
Parameter↓2 → IRI
optional
Parameter↓3 → Boolean
iriPattern
Operation↓1 → IRIPattern
query
Operation↓2 → Query
delete
Operation↓3 → Delete
parameters
Operation↓4 → Parameter*
noMatch
Operation
matchPattern
IRIrel × IRIPattern → Boolean
The processor MUST implement matchPattern as defined in Request Matching, using C = Ontology, TZ = iriPattern(operation) [[!JAX-RS]]
precedence
Operation × Integer → OperationPrecedence
precedence(operation, precedence) = (operation, precedence)
matchOperations
IRIrel × Operation* × Integer → OperationPrecedence*
matchOperations(irirel, operations, precedence) = cons(null(operations) → nil [] matchPattern(iriPattern(head(operations))) → precedence(head(operations), precedence * -1) [] nil, matchOperations(tail(operations), precedence))
Denotational semantics do not allow recursive function definitions as the one above. This would need to be reworked to be strictly formal.
matchPrecedences
IRIrel × Ontology × Integer → OperationPrecedence*
matchPrecedences(irirel, ontology, importLevel) = cons(matchOperations(irirel, operations(ontology)), null(imports(ontology)) → nil [] matchPrecedences(irirel, head(imports(ontology)), importLevel + 1))
Denotational semantics do not allow recursive function definitions as the one above. This would need to be reworked to be strictly formal.
topMatch
OperationPrecedence* → Operation + { NoMatch }
topMatch(opPrecedences) = null(opPrecedences) → NoMatch [] topMatch((operation1, precedence1), …, (operationi, precedencei), …, (operationn, precedencen)) = operationi : precedencei ≥ precedencej for all i, j
match
IRIrel × OntologyOperation + { NoMatch }
match(irirel, ontology) = topMatch(matchPrecedences(irirel, ontology, 0))
reqMatch
Request × AppOperation + { NoMatch }
reqMatch(request, app) = match(relativize(base(app), absolutePath(iri(request))))
decodeUri
String → String
decodeUri(encoded) = decoded such that fn:encode-for-uri(decoded) = encoded [[xpath-functions-31]]
cast
RDFTerm × IRIRDFTerm
cast(inputValue, targetType) = targetValue ∈ RDFTerm
The processor MUST implement cast as defined in XPath Constructor Functions [[!sparql11-query]]
tokenize
String → String*
tokenize(string, delimiter) = fn:tokenize(string, delimiter)
argumentPairs
String* → (String × String)*
argumentPairs(strings) = cons(null(strings) → nil [] (decodeUri(head(tokenize(head(strings), "="))), decodeUri(head(tail(tokenize(head(strings), "="))))), argumentPairs(tail(strings)))
Denotational semantics do not allow recursive function definitions as the one above. This would need to be reworked to be strictly formal.
argPairsByName
(String × String)* × String → (String × String)*
argPairsByName(argumentPairs, name) = cons(null(argumentPairs) → nil [] head(argumentPairs)↓1 = name → head(argumentPairs) [] nil, argPairsByName(tail(argumentPairs), name))
Denotational semantics do not allow recursive function definitions as the one above. This would need to be reworked to be strictly formal.
paramArgs
Parameter × (String × String)* → Argument*
paramArgs(parameter, argumentPairs) = null(argumentPairs) → nil [] cons((parameter, cast(head(argPairsByName(argumentPairs, name(parameter)))↓2, valueType(parameter))), paramArgs(parameter, tail(argumentPairs)))
paramListArgs
Parameter* × (String × String)* → Argument*
paramListArgs(parameters, argumentPairs) = null(parameters) → nil [] concat(paramArgs(head(parameters), argumentPairs), paramListArgs(tail(parameters), argumentPairs))
Denotational semantics do not allow recursive function definitions as the one above. This would need to be reworked to be strictly formal.
parameter
Argument↓1 → Parameter
value
Argument↓2 → RDFTerm
conNeg
RequestMediaType
The processor MUST implement conNeg as defined in Determining the MediaType of Responses [[!JAX-RS]]
variable
String → QueryVariable
argBindings
Argument* → QueryBinding*
argBindings(arguments) = cons(null(arguments) → nil [] (variable(name(parameter(head(arguments)))), value(head(arguments))), argBindings(arguments))
merge
Dataset × DatasetDataset
merge(dataset1, dataset2) = dataset ∈ Dataset
The processor MUST implement merge as defined in RDF Dataset [[!sparql11-query]]
state
IRI × Argument* → Dataset
This is the function that should describe the current application state. How do we convert from sets to triples? Parameters need to have IRIs.
readData
Request × AppDataset
readData(request, app) = execQuery(apply(query(reqMatch(request, app)), cons((variable(this), absolutePath(iri(request))), argBindings(paramListArgs(parameters(reqMatch(request, app)), argumentPairs(tokenize(queryString(iri(request)))))))), dataset(app))
deleteData
Request × AppDataset
deleteData(request, app) = execDelete(apply(delete(reqMatch(request, app)), cons((variable(this), absolutePath(iri(request))), argBindings(paramListArgs(parameters(reqMatch(request, app)), argumentPairs(tokenize(queryString(iri(request)))))))), dataset(app))

Valuation functions

Evaluation of response to request ∈ LDRequest:

LDResponse : LDRequestLDResponse × Dataset

LDResponse [[CRUDStatus RDFMediaType Dataset]] (request)
LDResponse [[CRUDStatus RDFMediaType Dataset]] (app(iri(request))) (request)
LDResponse [[CRUDStatus RDFMediaType Dataset]] (app) (request)
((reqMatch(request, app) = NoMatchNotFound []
method(request) = DeleteNoContent []
OK,
conNeg(request),
method(request) = Readmerge(readData(request, app), state(iri(request), paramListArgs(parameters(reqMatch(request, app)), argumentPairs(tokenize(queryString(iri(request))))))) []
empty),
method(request) = Readdataset(app) []
method(request) = Appendmerge(body(request), dataset(app)) []
method(request) = Updatemerge(body(request), deleteData(request, app)) []
method(request) = DeletedeleteData(request, app))

LDT over HTTP

Abstract syntax

HTTPRequest
HTTP-request ⊂ Request
HTTPResponse
HTTP-response ⊂ Response
HTTPStatus
HTTP-status ⊂ Status
HTTPMethod
HTTP-method ⊂ Method

HTTPRequest := HTTPMethod IRI | HTTPMethod IRI MediaType Body
HTTPResponse := HTTPStatus MediaType Body
HTTPMethod := GET | POST | PUT | DELETE
HTTPStatus := 200 OK | 204 No Content | 404 Not Found

Semantics

Domains

HTTPRequest
HTTPMethod × IRIabs × Body
HTTPResponse
HTTPStatus × MediaType × Body
HTTPMethod
{ GET, POST, PUT, DELETE } ⊂ Request Methods [[!HTTP11]]
HTTPStatus
{ 200 OK, 204 No Content, 404 Not Found } ⊂ Response Status Codes [[!HTTP11]]

Functions

httpMethodToCRUDMethodMapping
(CRUDMethod × HTTPMethod)*
((POST, Append), (GET, Read), (PUT, Update), (DELETE, Delete))
crudStatusToHTTPStatusMapping
(CRUDStatus × HTTPStatus)*
((NotFound, 404 Not Found), (NoContent, 204 No Content), (OK, 200 OK))
httpMethodToCRUDMethod
HTTPMethod × (CRUDMethod × HTTPMethod)* → CRUDMethod
httpMethodToCRUDMethod(httpMethod, methodMapping) = head(methodMapping)↓2 = httpMethod → head(methodMapping)↓1 [] httpMethodToCRUDMethod(httpMethod, tail(methodMapping))
Denotational semantics do not allow recursive domain definitions such as the one above. This would need to be reworked to be strictly formal.
crudStatusToHTTPStatus
CRUDStatus × (CRUDStatus × HTTPStatus)* → HTTPStatus
crudStatusToHTTPStatus(crudStatus, statusMapping) = head(statusMapping)↓1 = crudStatus → head(statusMapping)↓2 [] crudStatusToHTTPStatus(crudStatus, tail(statusMapping))
Denotational semantics do not allow recursive domain definitions such as the one above. This would need to be reworked to be strictly formal.

Valuation functions

Evaluation of response to request ∈ HTTPRequest:

HTTPResponse : HTTPRequestHTTPResponse × Dataset

HTTPResponse [[HTTPStatus MediaType Body]] (httpRequest)
(crudStatusToHTTPStatus(ldResponse↓1, crudStatusToHTTPStatusMapping), ldResponse↓2, ldResponse↓3) : ldResponse = (LDResponse [[CRUDStatus RDFMediaType Dataset]] ((httpMethodToCRUDMethod(method(httpRequest), httpMethodToCRUDMethodMapping), iri(httpRequest), mediaType(httpRequest), body(httpRequest))))

Examples

We will use the following set members for all the subsequent response valuation examples:

appApp
app(iri(request)) = (<https://linkeddatahub.com/>, ontology, dataset)
graphParamParameter
("g", <http://www.w3.org/2000/01/rdf-schema#Resource>, true)
matchOperation
reqMatch(request, app) = ("/people/{familyName}", describeWithTopic, deleteWithTopic, (graphParam))
describeWithTopicDescribe
PREFIX  foaf: <http://xmlns.com/foaf/0.1/>

DESCRIBE ?this ?primaryTopic
WHERE
  { GRAPH ?g
      { ?this  ?p  ?o
        OPTIONAL
          { ?this     foaf:primaryTopic  ?primaryTopic .
            ?primaryTopic
                      ?primaryTopicP     ?primaryTopicO
          }
      }
  }
deleteWithTopicDelete
PREFIX  foaf: <http://xmlns.com/foaf/0.1/>

DELETE {
  GRAPH ?g {
    ?this ?p ?o .
    ?primaryTopic ?primaryTopicP ?primaryTopicO .
  }
}
WHERE
  { GRAPH ?g
      { ?this ?p ?o
        OPTIONAL
          { ?this foaf:primaryTopic ?primaryTopic .
            ?primaryTopic ?primaryTopicP ?primaryTopicO
          }
      }
  }

Ontology

The following example shows the ontology of our example application. Operations used in response valuation are encoded as RDF terms using LDT vocabulary and SPIN vocabulary:

@prefix :     <https://linkeddatahub.com/ns#> .
@prefix ldt:  <https://www.w3.org/ns/ldt#> .
@prefix owl:  <http://www.w3.org/2002/07/owl#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix sp:   <http://spinrdf.org/sp#> .
@prefix spl:  <http://spinrdf.org/spl#> .

: a ldt:Ontology ;
  owl:imports ldt:, sp: ;
  rdfs:label "Example ontology" .

:PersonItem a ldt:Template ;
  rdfs:label "Person item" ;
  ldt:match "/people/{familyName}" ;
  ldt:param :GraphParam ;
  ldt:query :DescribeWithTopic ;
  ldt:update :DeleteWithTopic ;
  rdfs:isDefinedBy : .

:GraphParam a ldt:Parameter ;
  rdfs:label "Graph parameter" ;
  spl:predicate :g ;
  spl:valueType rdfs:Resource ;
  spl:optional true ;
  rdfs:isDefinedBy : .

:DescribeWithTopic a ldt:Query, sp:Describe ;
  rdfs:label "Describe with topic" ;
  sp:text """PREFIX  foaf: <http://xmlns.com/foaf/0.1/>

DESCRIBE ?this ?primaryTopic
WHERE
  { GRAPH ?g
      { ?this  ?p  ?o
        OPTIONAL
          { ?this     foaf:primaryTopic  ?primaryTopic .
            ?primaryTopic
                      ?primaryTopicP     ?primaryTopicO
          }
      }
  }""" ;
  rdfs:isDefinedBy : .

:DeleteWithTopic a ldt:Update, sp:Modify ;
  rdfs:label "Delete with topic" ;
  sp:text """PREFIX  foaf: <http://xmlns.com/foaf/0.1/>

DELETE {
  GRAPH ?g {
    ?this ?p ?o .
    ?primaryTopic ?primaryTopicP ?primaryTopicO .
  }
}
WHERE
  { GRAPH ?g
      { ?this ?p ?o
        OPTIONAL
          { ?this foaf:primaryTopic ?primaryTopic .
            ?primaryTopic ?primaryTopicP ?primaryTopicO
          }
      }
  }""" ;
  rdfs:isDefinedBy : .

Update over HTTP

The following example shows how an HTTP PUT request with an RDF dataset as its body evaluates as Linked Data Update request on an LDT application. The evaluation result is a successful HTTP response and operations on the application's dataset.

SPARQL update execution removes the existing description of the requested resource in the dataset. It is followed by a merge of the request body into the dataset. The updated application dataset is a side-effect of the interaction.

HTTP PUT request putRequest with request body putBody

PUT /people/Berners-Lee HTTP/1.1
Host: linkeddatahub.com
Accept: text/turtle, text/trig
Content-Type: text/trig

@base         <https://linkeddatahub.com/people/Berners-Lee> .
@prefix c:    <https://www.w3.org/ns/ldt/core/domain#> .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
@prefix owl:  <http://www.w3.org/2002/07/owl#> .

<../graphs/c5f34fe9-0456-48e8-a371-04be71529762>
{

  <> a c:Document ;
    foaf:primaryTopic <#this> .

  <#this> a foaf:Person ;
    foaf:isPrimaryTopicOf <> ;
    owl:sameAs <https://www.w3.org/People/Berners-Lee/card#i> .

}

Valuation of putRequest

HTTPResponse [[HTTPStatus MediaType Body]] (putRequest) =

(crudStatusToHTTPStatus(ldResponse↓1, crudStatusToHTTPStatusMapping), ldResponse↓2, ldResponse↓3) : ldResponse = (LDResponse [[CRUDStatus RDFMediaType Dataset]] ((httpMethodToCRUDMethod(method(putRequest), httpMethodToCRUDMethodMapping), iri(putRequest), mediaType(putRequest), body(putRequest))))↓1

ldResponse = (LDResponse [[CRUDStatus RDFMediaType Dataset]] ((httpMethodToCRUDMethod(method(putRequest), httpMethodToCRUDMethodMapping), iri(putRequest), mediaType(putRequest), body(putRequest))))↓1 =

(LDResponse [[CRUDStatus RDFMediaType Dataset]] ((httpMethodToCRUDMethod(PUT, httpMethodToCRUDMethodMapping), <https://linkeddatahub.com/people/Berners-Lee>, text/trig, putBody)))↓1 =

(LDResponse [[CRUDStatus RDFMediaType Dataset]] ((Update, <https://linkeddatahub.com/people/Berners-Lee>, text/trig, putBody)))↓1 =

(LDResponse [[CRUDStatus RDFMediaType Dataset]] (app(iri((Update, <https://linkeddatahub.com/people/Berners-Lee>, text/trig, putBody)))) ((Update, <https://linkeddatahub.com/people/Berners-Lee>, text/trig, putBody)))↓1 =

(LDResponse [[CRUDStatus RDFMediaType Dataset]] (app(<https://linkeddatahub.com/people/Berners-Lee>)) ((Update, <https://linkeddatahub.com/people/Berners-Lee>, text/trig, putBody)))↓1 =

(LDResponse [[CRUDStatus RDFMediaType Dataset]] ((<https://linkeddatahub.com/>, ontology, dataset)) ((Update, <https://linkeddatahub.com/people/Berners-Lee>, text/trig, putBody)))↓1 =

((reqMatch((Update, <https://linkeddatahub.com/people/Berners-Lee>, text/trig, putBody), (<https://linkeddatahub.com/>, ontology, dataset)) = NoMatch → NotFound []
method((Update, <https://linkeddatahub.com/people/Berners-Lee>, text/trig, putBody)) = Delete → NoContent []
OK,
conNeg((Update, <https://linkeddatahub.com/people/Berners-Lee>, text/trig, putBody)),
method((Update, <https://linkeddatahub.com/people/Berners-Lee>, text/trig, putBody)) = Read → merge(readData((Update, <https://linkeddatahub.com/people/Berners-Lee>, text/trig, putBody), (<https://linkeddatahub.com/>, ontology, dataset)), state(iri((Update, <https://linkeddatahub.com/people/Berners-Lee>, text/trig, putBody)), paramListArgs(parameters(reqMatch((Update, <https://linkeddatahub.com/people/Berners-Lee>, text/trig, putBody), (<https://linkeddatahub.com/>, ontology, dataset))), argumentPairs(tokenize(queryString(iri((Update, <https://linkeddatahub.com/people/Berners-Lee>, text/trig, putBody)))))))) []
method((Update, <https://linkeddatahub.com/people/Berners-Lee>, text/trig, putBody)) = Append → empty []
method((Update, <https://linkeddatahub.com/people/Berners-Lee>, text/trig, putBody)) = Update → empty []
method((Update, <https://linkeddatahub.com/people/Berners-Lee>, text/trig, putBody)) = Delete → empty),
method((Update, <https://linkeddatahub.com/people/Berners-Lee>, text/trig, putBody)) = Read → dataset((<https://linkeddatahub.com/>, ontology, dataset)) []
method((Update, <https://linkeddatahub.com/people/Berners-Lee>, text/trig, putBody)) = Append → merge(body((Update, <https://linkeddatahub.com/people/Berners-Lee>, text/trig, putBody)), dataset((<https://linkeddatahub.com/>, ontology, dataset))) []
method((Update, <https://linkeddatahub.com/people/Berners-Lee>, text/trig, putBody)) = Update → merge(body((Update, <https://linkeddatahub.com/people/Berners-Lee>, text/trig, putBody)), deleteData((Update, <https://linkeddatahub.com/people/Berners-Lee>, text/trig, putBody), (<https://linkeddatahub.com/>, ontology, dataset))) []
method((Update, <https://linkeddatahub.com/people/Berners-Lee>, text/trig, putBody)) = Delete → deleteData((Update, <https://linkeddatahub.com/people/Berners-Lee>, text/trig, putBody), (<https://linkeddatahub.com/>, ontology, dataset)))↓1 =

((match = NoMatch → NotFound []
Update = Delete → NoContent []
OK,
text/turtle,
Update = Read → merge(readData((Update, <https://linkeddatahub.com/people/Berners-Lee>, text/trig, putBody), (<https://linkeddatahub.com/>, ontology, dataset)), state(<https://linkeddatahub.com/people/Berners-Lee>, paramListArgs(parameters(match), argumentPairs(tokenize(queryString(<https://linkeddatahub.com/people/Berners-Lee>)))))) []
Update = Append → empty []
Update = Update → empty []
Update = Delete → empty),
Update = Read → dataset((<https://linkeddatahub.com/>, ontology, dataset)) []
Update = Append → merge(putBody, dataset((<https://linkeddatahub.com/>, ontology, dataset))) []
Update = Update → merge(putBody, deleteData((Update, <https://linkeddatahub.com/people/Berners-Lee>, text/trig, putBody), (<https://linkeddatahub.com/>, ontology, dataset))) []
Update = Delete → deleteData((Update, <https://linkeddatahub.com/people/Berners-Lee>, text/trig, putBody), (<https://linkeddatahub.com/>, ontology, dataset)))↓1 =

((OK, text/turtle, empty),
merge(putBody, deleteData((Update, <https://linkeddatahub.com/people/Berners-Lee>, text/trig, putBody), (<https://linkeddatahub.com/>, ontology, dataset))))↓1 =

((OK, text/turtle, empty),
merge(putBody, execDelete(apply(delete(reqMatch((Update, <https://linkeddatahub.com/people/Berners-Lee>, text/trig, putBody), (<https://linkeddatahub.com/>, ontology, dataset))), cons((variable(this), absolutePath(iri((Update, <https://linkeddatahub.com/people/Berners-Lee>, text/trig, putBody)))), argBindings(paramListArgs(parameters(reqMatch((Update, <https://linkeddatahub.com/people/Berners-Lee>, text/trig, putBody), (<https://linkeddatahub.com/>, ontology, dataset))), argumentPairs(tokenize(queryString(iri((Update, <https://linkeddatahub.com/people/Berners-Lee>, text/trig, putBody))))))))), dataset((<https://linkeddatahub.com/>, ontology, dataset)))))↓1 =

((OK, text/turtle, empty),
merge(putBody, execDelete(apply(delete(match), cons((variable(this), absolutePath(<https://linkeddatahub.com/people/Berners-Lee>)), argBindings(paramListArgs(parameters(match), argumentPairs(tokenize(queryString(<https://linkeddatahub.com/people/Berners-Lee>))))))), dataset)))↓1 =

((OK, text/turtle, empty),
merge(putBody, execDelete(apply(deleteWithTopic, cons((?this, <https://linkeddatahub.com/people/Berners-Lee>), argBindings(paramListArgs((graphParam), argumentPairs(tokenize("")))))), dataset)))↓1 =

((OK, text/turtle, empty),
merge(putBody, execDelete(apply("PREFIX  foaf: <http://xmlns.com/foaf/0.1/>

DELETE {
  GRAPH ?g {
    ?this ?p ?o .
    ?primaryTopic ?primaryTopicP ?primaryTopicO .
  }
}
WHERE
  { GRAPH ?g
      { ?this ?p ?o
        OPTIONAL
          { ?this foaf:primaryTopic ?primaryTopic .
            ?primaryTopic ?primaryTopicP ?primaryTopicO
          }
      }
  }", cons((?this, <https://linkeddatahub.com/people/Berners-Lee>), argBindings(paramListArgs((graphParam), argumentPairs(()))))), dataset)))↓1 =

((OK, text/turtle, empty),
merge(putBody, execDelete(apply("PREFIX  foaf: <http://xmlns.com/foaf/0.1/>

DELETE {
  GRAPH ?g {
    ?this ?p ?o .
    ?primaryTopic ?primaryTopicP ?primaryTopicO .
  }
}
WHERE
  { GRAPH ?g
      { ?this ?p ?o
        OPTIONAL
          { ?this foaf:primaryTopic ?primaryTopic .
            ?primaryTopic ?primaryTopicP ?primaryTopicO
          }
      }
  }", cons((?this, <https://linkeddatahub.com/people/Berners-Lee>), argBindings(paramListArgs((graphParam), ())))), dataset)))↓1 =

((OK, text/turtle, empty),
merge(putBody, execDelete(apply("PREFIX  foaf: <http://xmlns.com/foaf/0.1/>

DELETE {
  GRAPH ?g {
    ?this ?p ?o .
    ?primaryTopic ?primaryTopicP ?primaryTopicO .
  }
}
WHERE
  { GRAPH ?g
      { ?this ?p ?o
        OPTIONAL
          { ?this foaf:primaryTopic ?primaryTopic .
            ?primaryTopic ?primaryTopicP ?primaryTopicO
          }
      }
  }", cons((?this, <https://linkeddatahub.com/people/Berners-Lee>), argBindings(()))), dataset)))↓1 =

((OK, text/turtle, empty),
merge(putBody, execDelete(apply("PREFIX  foaf: <http://xmlns.com/foaf/0.1/>

DELETE {
  GRAPH ?g {
    ?this ?p ?o .
    ?primaryTopic ?primaryTopicP ?primaryTopicO .
  }
}
WHERE
  { GRAPH ?g
      { ?this ?p ?o
        OPTIONAL
          { ?this foaf:primaryTopic ?primaryTopic .
            ?primaryTopic ?primaryTopicP ?primaryTopicO
          }
      }
  }", cons((?this, <https://linkeddatahub.com/people/Berners-Lee>), ())), dataset)))↓1 =

((OK, text/turtle, empty),
merge(putBody, execDelete(apply("PREFIX  foaf: <http://xmlns.com/foaf/0.1/>

DELETE {
  GRAPH ?g {
    ?this ?p ?o .
    ?primaryTopic ?primaryTopicP ?primaryTopicO .
  }
}
WHERE
  { GRAPH ?g
      { ?this ?p ?o
        OPTIONAL
          { ?this foaf:primaryTopic ?primaryTopic .
            ?primaryTopic ?primaryTopicP ?primaryTopicO
          }
      }
  }", ((?this, <https://linkeddatahub.com/people/Berners-Lee>))), dataset)))↓1 =

((OK, text/turtle, empty),
merge(putBody, execDelete("PREFIX  foaf: <http://xmlns.com/foaf/0.1/>

DELETE {
  GRAPH ?g {
    <https://linkeddatahub.com/people/Berners-Lee> ?p ?o .
    ?primaryTopic ?primaryTopicP ?primaryTopicO .
  }
}
WHERE
  { GRAPH ?g
      { <https://linkeddatahub.com/people/Berners-Lee> ?p ?o
        OPTIONAL
          { <https://linkeddatahub.com/people/Berners-Lee> foaf:primaryTopic ?primaryTopic .
            ?primaryTopic ?primaryTopicP ?primaryTopicO
          }
      }
  }", dataset)))↓1

(crudStatusToHTTPStatus(ldResponse↓1, crudStatusToHTTPStatusMapping), ldResponse↓2, ldResponse↓3) =

(200 OK, text/turtle, empty)

HTTP response

HTTP/1.1 200 OK

Read over HTTP

The following example shows how an HTTP GET evaluates as Linked Data Read request on an LDT application. The evaluation result is a successful HTTP response with a body that is an RDF dataset. The dataset is a result of a SPARQL query execution on the application dataset, augmented with hypermedia arguments.

The request dereferences the IRI and retrieves the same representation that was stored by the previous example, to which the hypermedia state is appended.

HTTP GET request getRequest with query string arguments

GET /people/Berners-Lee?g=http%3A%2F%2Flinkeddatahub.com%2Fgraphs%2Fc5f34fe9-0456-48e8-a371-04be71529762 HTTP/1.1
Host: linkeddatahub.com
Accept: text/turtle, text/trig

Valuation of getRequest

HTTPResponse [[HTTPStatus MediaType Body]] (getRequest) =

(crudStatusToHTTPStatus(ldResponse↓1, crudStatusToHTTPStatusMapping), ldResponse↓2, ldResponse↓3) : ldResponse = (LDResponse [[CRUDStatus RDFMediaType Dataset]] ((httpMethodToCRUDMethod(method(getRequest), httpMethodToCRUDMethodMapping), iri(getRequest), mediaType(getRequest), body(getRequest))))↓1

ldResponse = (LDResponse [[CRUDStatus RDFMediaType Dataset]] ((httpMethodToCRUDMethod(method(getRequest), httpMethodToCRUDMethodMapping), iri(getRequest), mediaType(getRequest), body(getRequest))))↓1 =

(LDResponse [[CRUDStatus RDFMediaType Dataset]] ((httpMethodToCRUDMethod(GET, httpMethodToCRUDMethodMapping), <https://linkeddatahub.com/people/Berners-Lee?g=http%3A%2F%2Flinkeddatahub.com%2Fgraphs%2Fc5f34fe9-0456-48e8-a371-04be71529762>, NoType, empty)))↓1 =

(LDResponse [[CRUDStatus RDFMediaType Dataset]] ((Read, <https://linkeddatahub.com/people/Berners-Lee?g=http%3A%2F%2Flinkeddatahub.com%2Fgraphs%2Fc5f34fe9-0456-48e8-a371-04be71529762>, NoType, empty)))↓1 =

(LDResponse [[CRUDStatus RDFMediaType Dataset]] ((Read, <https://linkeddatahub.com/people/Berners-Lee?g=http%3A%2F%2Flinkeddatahub.com%2Fgraphs%2Fc5f34fe9-0456-48e8-a371-04be71529762>, NoType, empty)))↓1 =

(LDResponse [[CRUDStatus RDFMediaType Dataset]] (app(iri((Read, <https://linkeddatahub.com/people/Berners-Lee?g=http%3A%2F%2Flinkeddatahub.com%2Fgraphs%2Fc5f34fe9-0456-48e8-a371-04be71529762>, NoType, empty)))) ((Read, <https://linkeddatahub.com/people/Berners-Lee?g=http%3A%2F%2Flinkeddatahub.com%2Fgraphs%2Fc5f34fe9-0456-48e8-a371-04be71529762>, NoType, empty)))↓1 =

(LDResponse [[CRUDStatus RDFMediaType Dataset]] (app(<https://linkeddatahub.com/people/Berners-Lee?g=http%3A%2F%2Flinkeddatahub.com%2Fgraphs%2Fc5f34fe9-0456-48e8-a371-04be71529762>)) ((Read, <https://linkeddatahub.com/people/Berners-Lee?g=http%3A%2F%2Flinkeddatahub.com%2Fgraphs%2Fc5f34fe9-0456-48e8-a371-04be71529762>, NoType, empty)))↓1 =

(LDResponse [[CRUDStatus RDFMediaType Dataset]] ((<https://linkeddatahub.com/>, ontology, dataset)) ((Read, <https://linkeddatahub.com/people/Berners-Lee?g=http%3A%2F%2Flinkeddatahub.com%2Fgraphs%2Fc5f34fe9-0456-48e8-a371-04be71529762>, NoType, empty)))↓1 =

((reqMatch((Read, <https://linkeddatahub.com/people/Berners-Lee?g=http%3A%2F%2Flinkeddatahub.com%2Fgraphs%2Fc5f34fe9-0456-48e8-a371-04be71529762>, NoType, empty), app) = NoMatch → NotFound []
method((Read, <https://linkeddatahub.com/people/Berners-Lee?g=http%3A%2F%2Flinkeddatahub.com%2Fgraphs%2Fc5f34fe9-0456-48e8-a371-04be71529762>, NoType, empty)) = Delete → NoContent []
OK,
conNeg((Read, <https://linkeddatahub.com/people/Berners-Lee?g=http%3A%2F%2Flinkeddatahub.com%2Fgraphs%2Fc5f34fe9-0456-48e8-a371-04be71529762>, NoType, empty)),
method((Read, <https://linkeddatahub.com/people/Berners-Lee?g=http%3A%2F%2Flinkeddatahub.com%2Fgraphs%2Fc5f34fe9-0456-48e8-a371-04be71529762>, NoType, empty)) = Read → merge(readData((Read, <https://linkeddatahub.com/people/Berners-Lee?g=http%3A%2F%2Flinkeddatahub.com%2Fgraphs%2Fc5f34fe9-0456-48e8-a371-04be71529762>, NoType, empty), (<https://linkeddatahub.com/>, ontology, dataset)), state(iri((Read, <https://linkeddatahub.com/people/Berners-Lee?g=http%3A%2F%2Flinkeddatahub.com%2Fgraphs%2Fc5f34fe9-0456-48e8-a371-04be71529762>, NoType, empty)), paramListArgs(parameters(reqMatch((Read, <https://linkeddatahub.com/people/Berners-Lee?g=http%3A%2F%2Flinkeddatahub.com%2Fgraphs%2Fc5f34fe9-0456-48e8-a371-04be71529762>, NoType, empty), (<https://linkeddatahub.com/>, ontology, dataset))), argumentPairs(tokenize(queryString(iri((Read, <https://linkeddatahub.com/people/Berners-Lee?g=http%3A%2F%2Flinkeddatahub.com%2Fgraphs%2Fc5f34fe9-0456-48e8-a371-04be71529762>, NoType, empty)))))))) []
method((Read, <https://linkeddatahub.com/people/Berners-Lee?g=http%3A%2F%2Flinkeddatahub.com%2Fgraphs%2Fc5f34fe9-0456-48e8-a371-04be71529762>, NoType, empty)) = Append → empty []
method((Read, <https://linkeddatahub.com/people/Berners-Lee?g=http%3A%2F%2Flinkeddatahub.com%2Fgraphs%2Fc5f34fe9-0456-48e8-a371-04be71529762>, NoType, empty)) = Update → empty []
method((Read, <https://linkeddatahub.com/people/Berners-Lee?g=http%3A%2F%2Flinkeddatahub.com%2Fgraphs%2Fc5f34fe9-0456-48e8-a371-04be71529762>, NoType, empty)) = Delete → empty),
method((Read, <https://linkeddatahub.com/people/Berners-Lee?g=http%3A%2F%2Flinkeddatahub.com%2Fgraphs%2Fc5f34fe9-0456-48e8-a371-04be71529762>, NoType, empty)) = Read → dataset((<https://linkeddatahub.com/>, ontology, dataset)) []
method((Read, <https://linkeddatahub.com/people/Berners-Lee?g=http%3A%2F%2Flinkeddatahub.com%2Fgraphs%2Fc5f34fe9-0456-48e8-a371-04be71529762>, NoType, empty)) = Append → merge(body((Read, <https://linkeddatahub.com/people/Berners-Lee?g=http%3A%2F%2Flinkeddatahub.com%2Fgraphs%2Fc5f34fe9-0456-48e8-a371-04be71529762>, NoType, empty)), dataset((<https://linkeddatahub.com/>, ontology, dataset))) []
method((Read, <https://linkeddatahub.com/people/Berners-Lee?g=http%3A%2F%2Flinkeddatahub.com%2Fgraphs%2Fc5f34fe9-0456-48e8-a371-04be71529762>, NoType, empty)) = Update → merge(body((Read, <https://linkeddatahub.com/people/Berners-Lee?g=http%3A%2F%2Flinkeddatahub.com%2Fgraphs%2Fc5f34fe9-0456-48e8-a371-04be71529762>, NoType, empty)), deleteData((Read, <https://linkeddatahub.com/people/Berners-Lee?g=http%3A%2F%2Flinkeddatahub.com%2Fgraphs%2Fc5f34fe9-0456-48e8-a371-04be71529762>, NoType, empty), (<https://linkeddatahub.com/>, ontology, dataset))) []
method((Read, <https://linkeddatahub.com/people/Berners-Lee?g=http%3A%2F%2Flinkeddatahub.com%2Fgraphs%2Fc5f34fe9-0456-48e8-a371-04be71529762>, NoType, empty)) = Delete → deleteData((Read, <https://linkeddatahub.com/people/Berners-Lee?g=http%3A%2F%2Flinkeddatahub.com%2Fgraphs%2Fc5f34fe9-0456-48e8-a371-04be71529762>, NoType, empty), (<https://linkeddatahub.com/>, ontology, dataset)))↓1 =

((match = NoMatch → NotFound []
Read = Delete → NoContent []
OK,
text/trig,
Read = Read → merge(readData((Read, <https://linkeddatahub.com/people/Berners-Lee?g=http%3A%2F%2Flinkeddatahub.com%2Fgraphs%2Fc5f34fe9-0456-48e8-a371-04be71529762>, NoType, empty), (<https://linkeddatahub.com/>, ontology, dataset)), state(iri((Read, <https://linkeddatahub.com/people/Berners-Lee?g=http%3A%2F%2Flinkeddatahub.com%2Fgraphs%2Fc5f34fe9-0456-48e8-a371-04be71529762>, NoType, empty)), paramListArgs(parameters(match), argumentPairs(tokenize(queryString(iri((Read, <https://linkeddatahub.com/people/Berners-Lee?g=http%3A%2F%2Flinkeddatahub.com%2Fgraphs%2Fc5f34fe9-0456-48e8-a371-04be71529762>, NoType, empty)))))))) []
Read = Append → empty []
Read = Update → empty []
Read = Delete → empty),
Read = Read → dataset((<https://linkeddatahub.com/>, ontology, dataset)) []
Read = Append → merge(body((Read, <https://linkeddatahub.com/people/Berners-Lee?g=http%3A%2F%2Flinkeddatahub.com%2Fgraphs%2Fc5f34fe9-0456-48e8-a371-04be71529762>, NoType, empty)), dataset((<https://linkeddatahub.com/>, ontology, dataset))) []
Read = Update → merge(body((Read, <https://linkeddatahub.com/people/Berners-Lee?g=http%3A%2F%2Flinkeddatahub.com%2Fgraphs%2Fc5f34fe9-0456-48e8-a371-04be71529762>, NoType, empty)), deleteData((Read, <https://linkeddatahub.com/people/Berners-Lee?g=http%3A%2F%2Flinkeddatahub.com%2Fgraphs%2Fc5f34fe9-0456-48e8-a371-04be71529762>, NoType, empty), (<https://linkeddatahub.com/>, ontology, dataset))) []
Read = Delete → deleteData((Read, <https://linkeddatahub.com/people/Berners-Lee?g=http%3A%2F%2Flinkeddatahub.com%2Fgraphs%2Fc5f34fe9-0456-48e8-a371-04be71529762>, NoType, empty), (<https://linkeddatahub.com/>, ontology, dataset)))↓1 =

((OK, text/trig,
merge(readData((Read, <https://linkeddatahub.com/people/Berners-Lee?g=http%3A%2F%2Flinkeddatahub.com%2Fgraphs%2Fc5f34fe9-0456-48e8-a371-04be71529762>, NoType, empty), (<https://linkeddatahub.com/>, ontology, dataset)), state(iri((Read, <https://linkeddatahub.com/people/Berners-Lee?g=http%3A%2F%2Flinkeddatahub.com%2Fgraphs%2Fc5f34fe9-0456-48e8-a371-04be71529762>, NoType, empty)), paramListArgs(parameters(match), argumentPairs(tokenize(queryString(iri((Read, <https://linkeddatahub.com/people/Berners-Lee?g=http%3A%2F%2Flinkeddatahub.com%2Fgraphs%2Fc5f34fe9-0456-48e8-a371-04be71529762>, NoType, empty))))))))),
dataset((<https://linkeddatahub.com/>, ontology, dataset)))↓1 =

((OK, text/trig,
merge(execQuery(apply(query(reqMatch((Read, <https://linkeddatahub.com/people/Berners-Lee?g=http%3A%2F%2Flinkeddatahub.com%2Fgraphs%2Fc5f34fe9-0456-48e8-a371-04be71529762>, NoType, empty), (<https://linkeddatahub.com/>, ontology, dataset))), cons((variable(this), absolutePath(iri((Read, <https://linkeddatahub.com/people/Berners-Lee?g=http%3A%2F%2Flinkeddatahub.com%2Fgraphs%2Fc5f34fe9-0456-48e8-a371-04be71529762>, NoType, empty)))), argBindings(paramListArgs(parameters(reqMatch((Read, <https://linkeddatahub.com/people/Berners-Lee?g=http%3A%2F%2Flinkeddatahub.com%2Fgraphs%2Fc5f34fe9-0456-48e8-a371-04be71529762>, NoType, empty), (<https://linkeddatahub.com/>, ontology, dataset))), argumentPairs(tokenize(queryString(iri((Read, <https://linkeddatahub.com/people/Berners-Lee?g=http%3A%2F%2Flinkeddatahub.com%2Fgraphs%2Fc5f34fe9-0456-48e8-a371-04be71529762>, NoType, empty))))))))), dataset((<https://linkeddatahub.com/>, ontology, dataset))), state(<https://linkeddatahub.com/people/Berners-Lee?g=http%3A%2F%2Flinkeddatahub.com%2Fgraphs%2Fc5f34fe9-0456-48e8-a371-04be71529762>, paramListArgs(parameters(match), argumentPairs(tokenize(queryString(<https://linkeddatahub.com/people/Berners-Lee?g=http%3A%2F%2Flinkeddatahub.com%2Fgraphs%2Fc5f34fe9-0456-48e8-a371-04be71529762>))))))),
dataset)↓1 =

((OK, text/trig,
merge(execQuery(apply(query(match), cons((variable(this), absolutePath(iri((Read, <https://linkeddatahub.com/people/Berners-Lee?g=http%3A%2F%2Flinkeddatahub.com%2Fgraphs%2Fc5f34fe9-0456-48e8-a371-04be71529762>, NoType, empty)))), argBindings(paramListArgs(parameters(match), argumentPairs(tokenize(queryString(iri((Read, <https://linkeddatahub.com/people/Berners-Lee?g=http%3A%2F%2Flinkeddatahub.com%2Fgraphs%2Fc5f34fe9-0456-48e8-a371-04be71529762>, NoType, empty))))))))), dataset((<https://linkeddatahub.com/>, ontology, dataset))), state(<https://linkeddatahub.com/people/Berners-Lee?g=http%3A%2F%2Flinkeddatahub.com%2Fgraphs%2Fc5f34fe9-0456-48e8-a371-04be71529762>, paramListArgs(parameters(match), argumentPairs(tokenize(queryString(<https://linkeddatahub.com/people/Berners-Lee?g=http%3A%2F%2Flinkeddatahub.com%2Fgraphs%2Fc5f34fe9-0456-48e8-a371-04be71529762>))))))),
dataset)↓1 =

((OK, text/trig,
merge(execQuery(apply(describeWithTopic, cons((?this, absolutePath(<https://linkeddatahub.com/people/Berners-Lee?g=http%3A%2F%2Flinkeddatahub.com%2Fgraphs%2Fc5f34fe9-0456-48e8-a371-04be71529762>)), argBindings(paramListArgs((graphParam), argumentPairs(tokenize(queryString(<https://linkeddatahub.com/people/Berners-Lee?g=http%3A%2F%2Flinkeddatahub.com%2Fgraphs%2Fc5f34fe9-0456-48e8-a371-04be71529762>))))))), dataset), state(<https://linkeddatahub.com/people/Berners-Lee?g=http%3A%2F%2Flinkeddatahub.com%2Fgraphs%2Fc5f34fe9-0456-48e8-a371-04be71529762>, paramListArgs((graphParam), argumentPairs(tokenize("g=http%3A%2F%2Flinkeddatahub.com%2Fgraphs%2Fc5f34fe9-0456-48e8-a371-04be71529762")))))),
dataset)↓1 =

((OK, text/trig,
merge(execQuery(apply("PREFIX  foaf: <http://xmlns.com/foaf/0.1/>

DESCRIBE ?this ?primaryTopic
WHERE
  { GRAPH ?g
      { ?this  ?p  ?o
        OPTIONAL
          { ?this     foaf:primaryTopic  ?primaryTopic .
            ?primaryTopic
                      ?primaryTopicP     ?primaryTopicO
          }
      }
  }", cons((?this, <https://linkeddatahub.com/people/Berners-Lee>), argBindings(paramListArgs((graphParam), argumentPairs(tokenize("g=http%3A%2F%2Flinkeddatahub.com%2Fgraphs%2Fc5f34fe9-0456-48e8-a371-04be71529762")))))), dataset), state(<https://linkeddatahub.com/people/Berners-Lee?g=http%3A%2F%2Flinkeddatahub.com%2Fgraphs%2Fc5f34fe9-0456-48e8-a371-04be71529762>, paramListArgs((graphParam), (("g", "http://linkeddatahub.com/graphs/c5f34fe9-0456-48e8-a371-04be71529762")))))),
dataset)↓1 =

((OK, text/trig,
merge(execQuery(apply("PREFIX  foaf: <http://xmlns.com/foaf/0.1/>

DESCRIBE ?this ?primaryTopic
WHERE
  { GRAPH ?g
      { ?this  ?p  ?o
        OPTIONAL
          { ?this     foaf:primaryTopic  ?primaryTopic .
            ?primaryTopic
                      ?primaryTopicP     ?primaryTopicO
          }
      }
  }", cons((?this, <https://linkeddatahub.com/people/Berners-Lee>), argBindings(paramListArgs((graphParam), argumentPairs(("g", "http%3A%2F%2Flinkeddatahub.com%2Fgraphs%2Fc5f34fe9-0456-48e8-a371-04be71529762")))))), dataset), state(<https://linkeddatahub.com/people/Berners-Lee?g=http%3A%2F%2Flinkeddatahub.com%2Fgraphs%2Fc5f34fe9-0456-48e8-a371-04be71529762>, ((graphParam, >http://linkeddatahub.com/graphs/c5f34fe9-0456-48e8-a371-04be71529762<))))),
dataset)↓1 =

((OK, text/trig,
merge(execQuery(apply("PREFIX  foaf: <http://xmlns.com/foaf/0.1/>

DESCRIBE ?this ?primaryTopic
WHERE
  { GRAPH ?g
      { ?this  ?p  ?o
        OPTIONAL
          { ?this     foaf:primaryTopic  ?primaryTopic .
            ?primaryTopic
                      ?primaryTopicP     ?primaryTopicO
          }
      }
  }", cons((?this, <https://linkeddatahub.com/people/Berners-Lee>), argBindings(((graphParam, >http://linkeddatahub.com/graphs/c5f34fe9-0456-48e8-a371-04be71529762<))))), dataset), state(<https://linkeddatahub.com/people/Berners-Lee?g=http%3A%2F%2Flinkeddatahub.com%2Fgraphs%2Fc5f34fe9-0456-48e8-a371-04be71529762>, ((graphParam, >http://linkeddatahub.com/graphs/c5f34fe9-0456-48e8-a371-04be71529762<))))),
dataset)↓1 =

((OK, text/trig,
merge(execQuery(apply("PREFIX  foaf: <http://xmlns.com/foaf/0.1/>

DESCRIBE ?this ?primaryTopic
WHERE
  { GRAPH ?g
      { ?this  ?p  ?o
        OPTIONAL
          { ?this     foaf:primaryTopic  ?primaryTopic .
            ?primaryTopic
                      ?primaryTopicP     ?primaryTopicO
          }
      }
  }", cons((?this, <https://linkeddatahub.com/people/Berners-Lee>), ((?g, >http://linkeddatahub.com/graphs/c5f34fe9-0456-48e8-a371-04be71529762<)))), dataset), state(<https://linkeddatahub.com/people/Berners-Lee?g=http%3A%2F%2Flinkeddatahub.com%2Fgraphs%2Fc5f34fe9-0456-48e8-a371-04be71529762>, ((graphParam, >http://linkeddatahub.com/graphs/c5f34fe9-0456-48e8-a371-04be71529762<))))),
dataset)↓1 =

((OK, text/trig,
merge(execQuery(apply("PREFIX  foaf: <http://xmlns.com/foaf/0.1/>

DESCRIBE ?this ?primaryTopic
WHERE
  { GRAPH ?g
      { ?this  ?p  ?o
        OPTIONAL
          { ?this     foaf:primaryTopic  ?primaryTopic .
            ?primaryTopic
                      ?primaryTopicP     ?primaryTopicO
          }
      }
  }", ((?this, <https://linkeddatahub.com/people/Berners-Lee>), ((?g, >http://linkeddatahub.com/graphs/c5f34fe9-0456-48e8-a371-04be71529762<)))), dataset), state(<https://linkeddatahub.com/people/Berners-Lee?g=http%3A%2F%2Flinkeddatahub.com%2Fgraphs%2Fc5f34fe9-0456-48e8-a371-04be71529762>, ((graphParam, >http://linkeddatahub.com/graphs/c5f34fe9-0456-48e8-a371-04be71529762<))))),
dataset)↓1 =

((OK, text/trig,
merge(execQuery("PREFIX  foaf: <http://xmlns.com/foaf/0.1/>

DESCRIBE <https://linkeddatahub.com/people/Berners-Lee> ?primaryTopic
WHERE
  { GRAPH >http://linkeddatahub.com/graphs/c5f34fe9-0456-48e8-a371-04be71529762<
      { <https://linkeddatahub.com/people/Berners-Lee>  ?p  ?o
        OPTIONAL
          { <https://linkeddatahub.com/people/Berners-Lee>     foaf:primaryTopic  ?primaryTopic .
            ?primaryTopic
                      ?primaryTopicP     ?primaryTopicO
          }
      }
  }", dataset), state(<https://linkeddatahub.com/people/Berners-Lee?g=http%3A%2F%2Flinkeddatahub.com%2Fgraphs%2Fc5f34fe9-0456-48e8-a371-04be71529762>, ((graphParam, >http://linkeddatahub.com/graphs/c5f34fe9-0456-48e8-a371-04be71529762<))))),
dataset)↓1

HTTP response

HTTP/1.1 200 OK
Content-Type: text/trig

@base         <https://linkeddatahub.com/people/Berners-Lee> .
@prefix ldt:  <https://www.w3.org/ns/ldt#> .
@prefix c:    <https://www.w3.org/ns/ldt/core/domain#> .
@prefix rdf:  <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
@prefix owl:  <http://www.w3.org/2002/07/owl#> .

<../graphs/c5f34fe9-0456-48e8-a371-04be71529762>
{

  <> a c:Document ;
    foaf:primaryTopic <#this> .

  <#this> a foaf:Person ;
    foaf:isPrimaryTopicOf <> ;
    owl:sameAs <https://www.w3.org/People/Berners-Lee/card#i> .

}

<?g=http%3A%2F%2Flinkeddatahub.com%2Fgraphs%2Fc5f34fe9-0456-48e8-a371-04be71529762> ldt:arg [
  a <https://linkeddatahub.com/ns#GraphParam> ;
  ldt:paramName "g" ;
  rdf:value <https://linkeddatahub.com/graphs/c5f34fe9-0456-48e8-a371-04be71529762>
] .

Vocabulary

Namespaces used in this section
Prefix Namespace URI
ldt: https://www.w3.org/ns/ldt#
rdf: http://www.w3.org/1999/02/22-rdf-syntax-ns#
rdfs: http://www.w3.org/2000/01/rdf-schema#
xsd: http://www.w3.org/2001/XMLSchema#
sd: http://www.w3.org/ns/sparql-service-description#

Application

Applications are orthogonal to operations. Does it make sense to put them under the same namespace?

Application
Domain Property Range Cardinality
App ldt:Application ldt:base rdfs:Resource IRI +
App ldt:Application ldt:ontology ldt:Ontology Ontology 1
App ldt:Application ldt:service sd:Service ???? 1

Operation

Operation
Domain Property Range Cardinality
Operation ldt:Template ldt:match xsd:string IRIPattern 1
Operation ldt:Template ldt:query ldt:Query Query 1
Operation ldt:Template rdfs:isDefinedBy ldt:Ontology Ontology 1
Operation ldt:Template ldt:update ldt:Update Delete ?
Operation ldt:Template ldt:param ldt:Parameter Parameter *
Operation ldt:Template ldt:extends ldt:Template Operation 1

Should we align set names with RDF terms? I.e. ldt:Operation instead of ldt:Template?
The range of the rdfs: properties is not accurate here in terms of RDFS.

Operation (HTTP)
Domain Property Range Cardinality
Operation ldt:Template ldt:lang rdf:List(xsd:string) ?
Operation ldt:Template ldt:cacheControl xsd:string ?

The HTTP properties are not part of LDT over HTTP yet. We need to introduce HTTP headers.
Also core and HTTP probably should not be under the same namespace.

Hypermedia

Argument
Domain Property Range Cardinality
IRI rdfs:Resource ldt:arg Argument *