Backlinks
Create, read, update and delete documents using the Graph Store Protocol
Every document is also a named graph in the dataspace's RDF dataset. LinkedDataHub supports the SPARQL Graph Store Protocol's direct graph identification as the HTTP CRUD protocol for managing document data.
GSP indirect graph identification is not supported starting with LinkedDataHub version 5.x.
Methods
The API also supports the PATCH HTTP method which is optional in GSP. It accepts graph-scoped SPARQL updates that will modify the requested document.
Only the INSERT/WHERE and DELETE WHERE forms are supported; GRAPH patterns are not allowed.
Trailing slashes in document URIs are enforced using 308 Permanent Redirect responses.
| Method | Description | Success | Failure | Reason |
|---|---|---|---|---|
GET |
Returns the data of a document | 200 OK |
404 Not Found |
Document with request URI not found |
406 Not Acceptable |
Media type not supported | |||
POST |
Appends data to a document | 204 No Content |
400 Bad Request |
RDF syntax error |
404 Not Found |
Document with request URI not found | |||
413 Payload Too Large |
Request body too large | |||
415 Unsupported Media Type |
Media type not supported | |||
422 Unprocessable Entity |
Constraint violation in the resulting document | |||
PUT |
Upserts a document | 200 OK201 Created308 Permanent Redirect |
400 Bad Request |
RDF syntax error |
| Malformed document URI | ||||
413 Payload Too Large |
Request body too large | |||
415 Unsupported Media Type |
Media type not supported | |||
422 Unprocessable Entity |
Constraint violation in the resulting document | |||
DELETE |
Removes the requested document | 204 No Content |
404 Not Found |
Document with request URI not found |
405 Method Not Allowed |
Deleting root, owner, or secretary documents is not allowed | |||
PATCH |
Modifies a document using SPARQL Update | 204 No Content |
422 Unprocessable Entity |
SPARQL update is not a single graph-scoped INSERT/DELETE operation, or removes an rdf:type |
| Constraint violation in the updated document |
Any method may additionally answer 403 Forbidden — see Access control. Any method that writes may answer 428 Precondition Required when the request carries no precondition, or 412 Precondition Failed when the one it carries is out of date — see Conditional writes.
Document metadata
Since LinkedDataHub 5, the document hierarchy is managed automatically.
By default, LinkedDataHub treats an RDF document as an item by giving it the dh:Item type and attaching it to the parent container using sioc:has_container. If the client wants to create a container instead, it has to explicitly add the
dh:Container type on the document resource; the new container will be attached to its parent using
sioc:has_parent. In either case, the URI of the new document will be relative to its parent's.
LinkedDataHub will also manage additional document metadata, such as its owner and creation/modification timestamps.
For example, this HTTP request creating the Northwind regions container (Turtle syntax):
PUT /regions/ HTTP/1.1
Host: localhost:4443
Content-Type: text/turtle
@prefix dh: <https://w3id.org/atomgraph/linkeddatahub/document-hierarchy#> .
@prefix dct: <http://purl.org/dc/terms/> .
<> a dh:Container ;
dct:title "Regions" .will produce the following document triples:
@prefix dh: <https://w3id.org/atomgraph/linkeddatahub/document-hierarchy#> .
@prefix dct: <http://purl.org/dc/terms/> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix sioc: <http://rdfs.org/sioc/ns#> .
@prefix acl: <http://www.w3.org/ns/auth/acl#> .
<https://localhost:4443/regions/>
a dh:Container ;
dct:created "2025-03-31T21:46:21.984Z"^^xsd:dateTime ;
dct:creator <https://admin.localhost:4443/acl/agents/865c2431-8436-4ae8-b300-2a531a013cd0/#this> ;
dct:title "Regions" ;
sioc:has_parent <https://localhost:4443/> ;
acl:owner <https://admin.localhost:4443/acl/agents/865c2431-8436-4ae8-b300-2a531a013cd0/#this> .The HTTP request to produce a new item can be empty:
PUT /regions/1/ HTTP/1.1 Host: localhost:4443 Content-Type: text/turtle
It will create an item document with the following triples:
@prefix dh: <https://w3id.org/atomgraph/linkeddatahub/document-hierarchy#> .
@prefix dct: <http://purl.org/dc/terms/> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix sioc: <http://rdfs.org/sioc/ns#> .
@prefix acl: <http://www.w3.org/ns/auth/acl#> .
<https://localhost:4443/regions/1/>
a dh:Item ;
dct:created "2025-03-31T20:45:42.802Z"^^xsd:dateTime ;
dct:creator <https://admin.localhost:4443/acl/agents/865c2431-8436-4ae8-b300-2a531a013cd0/#this> ;
sioc:has_container <https://localhost:4443/regions/> ;
acl:owner <https://admin.localhost:4443/acl/agents/865c2431-8436-4ae8-b300-2a531a013cd0/#this> .Graph-scoped updates
A PATCH applies a SPARQL update scoped to the requested document's graph. The request body
must contain a single update operation, in one of two forms: DELETE/INSERT with a WHERE clause (either template can be omitted, giving plain INSERT { } WHERE { } or DELETE { } WHERE { }), or the DELETE WHERE shorthand. Every other form is rejected with 422 Unprocessable Entity, as is a body with more than one operation. Appending a description to the Chai product:
PATCH /products/1/ HTTP/1.1
Host: localhost:4443
Content-Type: application/sparql-update
PREFIX schema: <https://schema.org/>
INSERT
{
<https://localhost:4443/products/1/#this> schema:description "A delicate black tea blend" .
}
WHERE {}The update executes against that one graph, so GRAPH patterns are not allowed — this request is rejected with
422 Unprocessable Entity:
PATCH /products/1/ HTTP/1.1
Host: localhost:4443
Content-Type: application/sparql-update
PREFIX schema: <https://schema.org/>
INSERT
{
GRAPH <https://localhost:4443/products/1/> # GRAPH is implied by the request URI — not allowed here
{
<https://localhost:4443/products/1/#this> schema:description "A delicate black tea blend" .
}
}
WHERE {}Built-in constraints
LinkedDataHub has a few built-in constraints that are not found in the standard Graph Store Protocol:
- It is not possible to delete the root document (returns
405 Method Not Allowed) - It is not possible to modify or delete the documents of the owner agent and the secretary
agent (returns
405 Method Not Allowed) - A document can only be created with a URL relative to an existing container (i.e. resolving .. against the new document's URL must identify an existing container)
The built-in constraints are similar to, but separate from the ontology constraints —
SPIN constraints and
SHACL shapes declared in the dataspace's ontology. Those are checked against the
document as the write leaves it, not the request body alone, so a POST or PATCH need not repeat the properties the
document already holds, and one that leaves the document invalid is answered 422 Unprocessable Entity.
Conditional writes
A write to a document that already exists must say which state it was written against. Every write reads the document's graph, changes it in memory and writes the whole graph back, so two writers that name no precondition overwrite each other with nothing to show that anything was lost.
Such a write is answered 428 Precondition Required. To make it conditional, send either:
If-Matchwith the document's currentETag, to modify what you readIf-None-Match: *, to create a document only if it does not exist yet
Creating a document needs no precondition — there is no prior state to have been written
against — so a PUT to a URL that does not exist is accepted as it always was.
If the document changed since you read it, the write is refused 412 Precondition Failed, and that response carries the document's current ETag so you can re-read, reapply your change and retry without an extra request. If-None-Match: * against a document that already exists is likewise refused 412, which is how a client can create-or-append in two steps.
An ETag identifies a negotiated representation, not the graph alone: the same document answers a different tag as RDF/XML than as
Turtle. Read the validator with the same Accept the write will send, or the write is refused 412.
HEAD /my/document/ HTTP/1.1 Accept: application/n-triples HTTP/1.1 200 OK ETag: "f731c06f5ac4fec6490dff1399bd5440" PATCH /my/document/ HTTP/1.1 Accept: application/n-triples Content-Type: application/sparql-update If-Match: "f731c06f5ac4fec6490dff1399bd5440" HTTP/1.1 204 No Content
HEAD is answered for any access mode the agent holds, not acl:Read alone, so an agent granted acl:Write or acl:Append can read the validator its writes have to quote without being able to read the document.
GET still requires acl:Read.
The command line interface does this for you: every ldh command that writes reads the document's validator first and sends it.
Versioned documents
In dataspaces with versioning enabled, document URLs accept additional query parameters that expose the version history through the standard Memento (RFC 7089) protocol:
?version=<commit-sha>- A historical version of the document, served with a
Memento-Datetimeheader and an immutableCache-Control. Snapshots are read-only: write methods answer405 Method Not Allowed ?timemap- The document's version history — a TimeMap described with PROV-O in RDF formats, or
in
application/link-formatas RFC 7089 requires ?timegate- Datetime negotiation: a request with an
Accept-Datetimeheader answers302 Foundwith the closest version inLocation
See the versioning reference for details.