Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions docs/reference/command-line-interface.ttl
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,9 @@ ldh add file \\
<p>See also the <a href="../../user-guide/import-data/">data import user guides</a>.</p>
<h3 id="request-bodies">Request bodies</h3>
<p><samp>ldh put</samp> and <samp>ldh post</samp> read RDF from an optional <samp>FILE</samp> argument, recognizing the syntax from its extension (<samp>ldh put "$LDH_BASE" root.ttl</samp>), or from standard input, where <code>-t</code>/<code>--content-type</code> is required since a stream carries no name. Either way relative URIs resolve against the target URI. <samp>ldh patch</samp> reads a SPARQL 1.1 update from standard input, validates it and sends it verbatim.</p>
<h3 id="create-only">Creating, not replacing</h3>
<p><samp>ldh create container</samp> and <samp>ldh create item</samp> only create: the <code>PUT</code> carries <code>If-None-Match: *</code>, so a document already at the URI is refused <samp>412 Precondition Failed</samp> and left as it is, and the command exits <samp>1</samp> with nothing on standard output. <code>--if-absent</code> accepts that document instead, as <samp>mkdir -p</samp> does a directory: the command exits <samp>0</samp> and prints its URL, so a setup script can run again. To replace a document, <samp>ldh put</samp> it.</p>
<pre>container=$(ldh create container --parent "$LDH_BASE" --title "Categories" --slug categories --if-absent)</pre>
<h3 id="primary-topic">What a document is about</h3>
<p><samp>ldh create item</samp> and <samp>ldh create container</samp> take <code>--primary-topic</code>, the resource the document is about, resolved against the created document's URI: <samp>'#this'</samp> names a fragment of the document itself, an absolute URI a resource described somewhere else. It writes the <code>foaf:primaryTopic</code> link only — the topic's own type and properties are the <a href="../administration/ontologies/#constructors">constructor</a>'s business, and a vocabulary may refuse a topic without them.</p>
<pre>ldh create item \\
Expand Down
3 changes: 3 additions & 0 deletions docs/reference/http-api.ttl
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@
</tr>
</tbody>
</table>
<p>The <code>accept</code> query parameter stands in for the <code>Accept</code> header where a link cannot set one, as in
<samp>?accept=text%2Fturtle</samp>. Its value is a media type and has to be URL-encoded: a malformed one, such as an unencoded
<samp>?accept=application/rdf+xml</samp> whose <code>+</code> decodes to a space, is answered <code>400 Bad Request</code>.</p>
<p>The same document, negotiated as N-Triples:</p>
<pre>GET /products/1/ HTTP/1.1
Host: localhost:4443
Expand Down
56 changes: 42 additions & 14 deletions docs/reference/http-api/documents.ttl
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@
<td><a href="../#con-neg">Media type</a> not supported</td>
</tr>
<tr>
<th rowspan="7" scope="row"><code id="ld-post">POST</code></th>
<td rowspan="7">Appends data to a document</td>
<td rowspan="7"><code>204 No Content</code></td>
<th rowspan="8" scope="row"><code id="ld-post">POST</code></th>
<td rowspan="8">Appends data to a document</td>
<td rowspan="8"><code>204 No Content</code></td>
<td><code>400 Bad Request</code></td>
<td>RDF syntax error</td>
</tr>
Expand All @@ -67,19 +67,22 @@
<td><a href="../#con-neg">Media type</a> not supported</td>
</tr>
<tr>
<td rowspan="3"><code>422 Unprocessable Entity</code></td>
<td rowspan="4"><code>422 Unprocessable Entity</code></td>
<td><a href="../../administration/ontologies/#constraints">Constraint</a> violation in the resulting document</td>
</tr>
<tr>
<td>Body states the <code>sioc:has_parent</code>/<code>sioc:has_container</code> of a resource other than the document</td>
</tr>
<tr>
<td>Body types the document with a class other than <code>def:Root</code>, <code>dh:Container</code> and <code>dh:Item</code>, or leaves the root without one of them</td>
</tr>
<tr>
<td>Malformed IRI in the body (see <a href="#malformed-iris">below</a>)</td>
</tr>
<tr>
<th rowspan="8" scope="row"><code id="ld-put">PUT</code></th>
<td rowspan="8">Upserts a document</td>
<td rowspan="8"><code>204 No Content</code> (replaced)<br></br><code>201 Created</code> (created)<br></br><code>308 Permanent Redirect</code></td>
<th rowspan="9" scope="row"><code id="ld-put">PUT</code></th>
<td rowspan="9">Upserts a document</td>
<td rowspan="9"><code>204 No Content</code> (replaced)<br></br><code>201 Created</code> (created)<br></br><code>308 Permanent Redirect</code></td>
<td rowspan="2"><code>400 Bad Request</code></td>
<td>RDF syntax error</td>
</tr>
Expand All @@ -99,12 +102,15 @@
<td><a href="../#con-neg">Media type</a> not supported</td>
</tr>
<tr>
<td rowspan="3"><code>422 Unprocessable Entity</code></td>
<td rowspan="4"><code>422 Unprocessable Entity</code></td>
<td><a href="../../administration/ontologies/#constraints">Constraint</a> violation in the resulting document</td>
</tr>
<tr>
<td>Body states the <code>sioc:has_parent</code>/<code>sioc:has_container</code> of a resource other than the document</td>
</tr>
<tr>
<td>Body types the document with a class other than <code>def:Root</code>, <code>dh:Container</code> and <code>dh:Item</code>, or leaves the root without one of them</td>
</tr>
<tr>
<td>Malformed IRI in the body (see <a href="#malformed-iris">below</a>)</td>
</tr>
Expand All @@ -124,11 +130,14 @@
<td>The container still has documents: delete them first</td>
</tr>
<tr>
<th rowspan="4" scope="row"><code id="ld-patch">PATCH</code></th>
<td rowspan="4">Modifies a document using SPARQL Update</td>
<td rowspan="4"><code>204 No Content</code></td>
<td rowspan="4"><code>422 Unprocessable Entity</code></td>
<td>SPARQL update is not a single <code>DELETE</code>/<code>INSERT</code> … <code>WHERE</code> or <code>DELETE WHERE</code> operation, uses <code>GRAPH</code>, <code>WITH</code>, <code>USING</code> or <code>USING NAMED</code>, or removes an <code>rdf:type</code></td>
<th rowspan="5" scope="row"><code id="ld-patch">PATCH</code></th>
<td rowspan="5">Modifies a document using SPARQL Update</td>
<td rowspan="5"><code>204 No Content</code></td>
<td rowspan="5"><code>422 Unprocessable Entity</code></td>
<td>SPARQL update has an operation other than <code>DELETE</code>/<code>INSERT</code> … <code>WHERE</code>, <code>DELETE WHERE</code>, <code>INSERT DATA</code> and <code>DELETE DATA</code>, uses <code>GRAPH</code>, <code>WITH</code>, <code>USING</code> or <code>USING NAMED</code>, or removes an <code>rdf:type</code></td>
</tr>
<tr>
<td>Update types the document with a class other than <code>def:Root</code>, <code>dh:Container</code> and <code>dh:Item</code>, or leaves it without one of them</td>
</tr>
<tr>
<td><a href="../../administration/ontologies/#constraints">Constraint</a> violation in the updated document</td>
Expand All @@ -152,6 +161,8 @@
<p>Containment is server-managed: a <code>POST</code> drops the document's <code>sioc:has_parent</code>/<code>sioc:has_container</code> from its body,
a <code>PATCH</code> cannot change them, and no write may state the containment of another resource. <a href="../../administration/acl/#authorizations"><code>acl:default</code></a>
grants rely on it.</p>
<p>A document is typed with the hierarchy classes only — <code>def:Root</code>, <code>dh:Container</code> or <code>dh:Item</code> — and a write that gives it any other type is refused with <code>422 Unprocessable Entity</code>, as is a <code>PUT</code> of the root or a
<code>PATCH</code> that leaves the document with none of them. Other classes belong on the resources the document describes, such as its <code>foaf:primaryTopic</code>.</p>
<p>LinkedDataHub will also manage additional document metadata, such as its owner and creation/modification timestamps.</p>
<p>For example, this HTTP request creating the Northwind regions container (Turtle syntax):</p>
<pre>PUT /regions/ HTTP/1.1
Expand Down Expand Up @@ -199,7 +210,7 @@ If-None-Match: *</pre>
</div>
<div>
<h2 id="patch-example">Graph-scoped updates</h2>
<p>A <code>PATCH</code> 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: <code>DELETE</code>/<code>INSERT</code> with a <code>WHERE</code> clause (either template can be omitted, giving plain <code>INSERT { } WHERE { }</code> or <code>DELETE { } WHERE { }</code>), or the <code>DELETE WHERE</code> shorthand. Every other form is rejected with <samp>422 Unprocessable Entity</samp>, as is a body with more than one operation. Like any write to an existing document, it quotes the document's entity tag (see <a href="#preconditions">Conditional writes</a>). Appending a description to the Chai product:</p>
<p>A <code>PATCH</code> applies a SPARQL update scoped to the requested document's graph. The request body contains one or more update operations, separated by <code>;</code>, in any of these forms: <code>DELETE</code>/<code>INSERT</code> with a <code>WHERE</code> clause (either template can be omitted, giving plain <code>INSERT { } WHERE { }</code> or <code>DELETE { } WHERE { }</code>), the <code>DELETE WHERE</code> shorthand, <code>INSERT DATA</code> and <code>DELETE DATA</code>. Every other form is rejected with <samp>422 Unprocessable Entity</samp>. The operations run in order, and the document is validated once they all have: they change it together or not at all. Like any write to an existing document, it quotes the document's entity tag (see <a href="#preconditions">Conditional writes</a>). Appending a description to the Chai product:</p>
<pre>PATCH /products/1/ HTTP/1.1
Host: localhost:4443
Accept: application/n-triples
Expand All @@ -213,6 +224,23 @@ INSERT
&lt;https://localhost:4443/products/1/#this&gt; schema:description "A delicate black tea blend" .
}
WHERE {}</pre>
<p>Replacing the product's name, as two operations applied together:</p>
<pre>PATCH /products/1/ HTTP/1.1
Host: localhost:4443
Accept: application/n-triples
Content-Type: application/sparql-update
If-Match: "1e635b4-ntriples"

PREFIX schema: &lt;https://schema.org/&gt;

DELETE DATA
{
&lt;https://localhost:4443/products/1/#this&gt; schema:name "Chai" .
} ;
INSERT DATA
{
&lt;https://localhost:4443/products/1/#this&gt; schema:name "Masala Chai" .
}</pre>
<p>The update executes against that one graph, so it cannot name another: <code>GRAPH</code> is not allowed in a template, in the <code>WHERE</code> pattern (including <code>EXISTS</code> and sub-queries) or in a <code>DELETE WHERE</code>, and neither are <code>WITH</code>, <code>USING</code> and <code>USING NAMED</code>. This request is rejected with
<samp>422 Unprocessable Entity</samp>:</p>
<pre>PATCH /products/1/ HTTP/1.1
Expand Down
2 changes: 2 additions & 0 deletions docs/reference/http-api/linked-data-proxy.ttl
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
schema:telephone "(171) 555-2222" .</pre>
<p>An HTML page with no JSON-LD has no RDF representation, so the proxy answers <code>406 Not Acceptable</code>. The user interface then opens the
page in a new browser tab, as an ordinary external link would.</p>
<p>Any other non-RDF body, such as an image, is passed through when its media type matches the request's <code>Accept</code>, and answered
<code>406 Not Acceptable</code> otherwise. An object block whose value is an external image requests RDF, gets the <code>406</code> and shows the image.</p>
<p>The proxy only accepts external (non-relative to the current dataspace's base URI) URLs; local URLs have to be dereferenced directly.</p>
<p>The proxy forwards the origin's <code>ETag</code> and <code>Last-Modified</code> validators and passes conditional request headers
(<code>If-Match</code>, <code>If-None-Match</code>, <code>If-Modified-Since</code>, <code>If-Unmodified-Since</code>) through. Preconditioned
Expand Down
14 changes: 12 additions & 2 deletions docs/reference/versioning.ttl
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,16 @@ HTTP/1.1 302 Found
Location: https://localhost:4443/orders/10248/?version=4d1e7aa
Vary: accept-datetime
Link: &lt;https://localhost:4443/orders/10248/&gt;; rel="original"</pre>
<p id="timegate-pending">A version is committed after the write that makes it. While the document's latest change is still being committed, the most
recent version would be the one before it, so the TimeGate answers <code>503 Service Unavailable</code> with <code>Retry-After</code> instead:
a second per commit queued on the dataspace's branch, at most 60. After a commit that failed, it answers <code>500 Internal Server Error</code>
until the next write is committed.</p>
<pre>GET /orders/10248/?timegate HTTP/1.1
Host: localhost:4443

HTTP/1.1 503 Service Unavailable
Retry-After: 3
Cache-Control: no-store</pre>
</div>
<div>
<h2 id="restore-diff">Restore and diff</h2>
Expand Down Expand Up @@ -163,15 +173,15 @@ Link: &lt;https://localhost:4443/orders/10248/&gt;; rel="original"</pre>
<tbody>
<tr>
<th scope="row"><samp>--timemap</samp></th>
<td>The version history (PROV-O in RDF formats, or <code>application/link-format</code> via <samp>--accept</samp>)</td>
<td>The version history (PROV-O in RDF formats, or <code>application/link-format</code> via <samp>--accept</samp>), from the <code>timemap</code> the document links to</td>
</tr>
<tr>
<th scope="row"><samp>--version &lt;sha&gt;</samp></th>
<td>The historical version at the given commit</td>
</tr>
<tr>
<th scope="row"><samp>--timegate</samp></th>
<td>Datetime negotiation; the optional <samp>--datetime</samp> takes an RFC 1123 or ISO 8601 datetime. Prints the negotiated version's URI as the only line on stdout, so it pipes into another <samp>ldh get</samp></td>
<td>Datetime negotiation with the <code>timegate</code> the document links to; the optional <samp>--datetime</samp> takes an RFC 1123 or ISO 8601 datetime. Waits as a <a href="#timegate-pending"><code>503</code></a>'s <code>Retry-After</code> asks, then prints the negotiated version's URI as the only line on stdout, so it pipes into another <samp>ldh get</samp></td>
</tr>
</tbody>
</table>
Expand Down
Loading