Backlinks
Make the app reproducible: a git repository that installs into any instance
Every stage so far produced files — document descriptions, mapping queries, CSV data, media. Kept in a repository with a small install script, they are the dataspace: versionable, diffable, reviewable, and replayable into any LinkedDataHub instance with ldh push. This is the layout the Northwind Traders repository uses:
northwind-traders/ ├── root.ttl # the target document itself ├── categories.ttl # one RDF file per document... ├── categories/ # ...and a folder for the files it holds │ ├── categories.csv │ ├── categories.rq │ └── *.jpg ├── admin/model/ │ ├── ns.ttl # the namespace ontology │ └── patch-ontology.ru # resets it before re-import ├── imports.csv # the CSV import manifest ├── install.sh # replays everything against $LDH_BASE ├── .ldhignore # files that are neither documents nor uploads └── Makefile
Source: demo/northwind-traders · Live: northwind-traders.demo.linkeddatahub.com
To follow along, clone the apps repository — git clone https://github.com/AtomGraph/LinkedDataHub-Apps, the demo lives in demo/northwind-traders — or assemble the files from the previous stages into a folder of the same shape.
The convention
The document URL is derived from the file path: categories.ttl installs to ${base}categories/, and root.ttl at the top of the tree is the
target document ${base} itself. ldh push walks the tree applying that rule: an RDF
file is PUT to the document its path spells, with its relative URIs resolved against that URL;
every other file is uploaded into its folder's document; a subfolder
recurses under the child document the RDF file beside it describes. Anything matched
by .ldhignore is skipped:
admin/ Makefile imports.csv screenshot.gif unesco-mappings.ttl *.csv *.sh
The patterns apply to the whole subtree below the ignore file, gitignore-style. A name pattern matches at any depth, so entries need not appear in the tree above: unesco-mappings.ttl excludes categories/unesco-mappings.ttl, which is import material rather than a document, and screenshot.gif excludes the repository's own screenshot, which is not app media. A trailing slash restricts a pattern to directories, so admin/ keeps the ontology sources out of the document tree. Nothing is excluded by default beyond hidden entries, so *.sh keeps the scripts from being uploaded, and *.csv leaves the data files to the CSV imports, which upload each one into the document it is imported into.
ldh push --dry-run "$LDH_BASE" # print the plan, send nothing ldh push "$LDH_BASE"
Idempotency
Re-running the install converges on the same documents instead of duplicating data.
PUT replaces each document's description outright, and the one place that appends rather
than replaces — the
namespace ontology — is first reset by patch-ontology.ru, a SPARQL update that clears everything except the ontology document's own description.
(The steps that create rather than replace —
make-public and each CSV import — are POSTs, so a re-run records another authorization and another import; the documents the
imports write are the same.)
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
DELETE {
?s ?p ?o
}
WHERE {
?s ?p ?o
# Exclude triples about the main resource itself
MINUS {
<> ?p ?o
BIND(<> AS ?s)
}
# Exclude triples about the foaf:primaryTopic resource
MINUS {
<> foaf:primaryTopic ?primaryTopic .
?primaryTopic ?p ?o
BIND(?primaryTopic AS ?s)
}
}Source: admin/model/patch-ontology.ru
Installing
make install
make install prompts for the base URI, certificate path, certificate password and an optional proxy URL, exports them as the LDH_BASE, LDH_CERT_FILE, LDH_CERT_PASSWORD and LDH_PROXY variables the CLI reads, then runs install.sh: ldh admin make-public, the namespace ontology install, ldh push, and one ldh import csv per row of the manifest. The entire tutorial, replayed in one command — against localhost today, against production tomorrow. Export the variables yourself and run ./install.sh to install without the prompts.
What you now see
The install prints a banner per step — ### Creating authorization to make the app public, ### Importing namespace ontology, ### Pushing documents and files (with one PUT or POST line per document or upload), ### Importing CSV data. When it finishes, open the base URI: the finished app renders, with no certificate required — the first step made it public.
How this works
- Command line interface — one command per HTTP API operation, scriptable and replayable
- HTTP API — the
PUTsemantics that make the replay idempotent
Next: Beyond low-code