This is the fabric-ld module, providing an extensible, component
based Linked Data HTTP server & query endpoint setup around a
FactGraph
(and underlying generic compute graph, both defined in
other modules of this project).
- Facts, queries and inference rules can be added/removed via a RESTstyle API
- Fact import from 3rd party URIs (as EDN or N-Triples)
- Supported response types: EDN, JSON, JSON-LD, SPARQL JSON results, CSV
- One-off queries or registered queries (latter automatically updated on fact set change)
- Registered queries return results immediately (without incurring work each time)
- Registered query results can be modified to filter/transform existing results
- Graph modifications are processed via core.async work queue & execution context
- All graph changes (facts) are written to disk (customizable, by default as EDN)
- Default config uses Zach Tellman’s Aleph server and deferred handlers
ALPHA quality, in active development.
(require '[thi.ng.fabric.ld.core :as ld])
;; launch server with default config (port 8000)
(ld/launch)
;; restart system (autoreloads ns)
(ld/reset)
;; stop entire system
(ld/stop)
Then from the command line (e.g. using httpie instead of curl for brevity):
# add facts in EDN format about this project
# EDN maps are a concise way to declare multiple relationships for
# for a common subject and are automatically resolved to triples
http -f POST :8000/facts \
facts='{"projects:fabric"
{"rdf:type" "foaf:Project"
"schema:isPartOf" "projects:thing"
"dcterms:creator" "people:toxi"}}'
# {:body "adding 3 facts"}
# EDN vectors in object position produce multiple triples
# with same subject & predicate
http -f POST :8000/facts \
facts='{"projects:fabric" {"schema:hasPart" ["fabric-core" "fabric-facts" "fabric-ld"]}}'
# {:body "adding 3 facts"}
# facts can also be imported from URIs (currently EDN or N-Triples only)
http -f POST :8000/facts uri=http://schema.org/version/2.0/schema.nt
# {:body "adding 9023 facts from http://schema.org/version/2.0/schema.nt"}
Supported response formats for triple dumps:
application/edn
(default)application/json
application/ld+json
text/csv
(limit
and offset
params are optional and default to 100/0)
# retrieve all facts as CSV
# (includes facts from default graph added on startup)
# known vocabulary prefixes are expanded to full URIs
http :8000/facts accept:text/csv limit==5 offset==5000
# subject,predicate,object
# <http://schema.org/DigitalAudioTapeFormat>,<http://www.w3.org/1999/02/22-rdf-syntax-ns#type>,<http://schema.org/Intangible>
# <http://schema.org/Canal>,<http://www.w3.org/2000/01/rdf-schema#subClassOf>,<http://schema.org/Thing>
# <http://schema.org/educationalAlignment>,<http://schema.org/rangeIncludes>,<http://schema.org/AlignmentObject>
# <http://schema.org/RsvpAction>,<http://www.w3.org/2000/01/rdf-schema#comment>,The act of notifying an event organizer as to whether you expect to attend the event.
# <http://schema.org/volumeNumber>,<http://schema.org/rangeIncludes>,<http://schema.org/Integer>
Query specs are defined via EDN using the DSL of the fabric-facts module.
# register query: find all projects and all their facts, group by project
http -f POST :8000/queries \
id=projects \
spec='{:q [{:where [[?prj "rdf:type" "foaf:Project"] [?prj ?p ?o]]}]
:order ?p
:group-by ?prj
:select [?p ?o]}'
# {:id "projects", :body "New query registered"}
Retrieves list of all registered queries. Their results are immediately available.
# list registered queries
http :8000/queries
# {:body {"types" {:q [{:where [[?s "rdf:type" ?type]]}]},
# "projects" {:q [{:where [[?prj "rdf:type" "foaf:Project"] [?prj ?p ?o]]}], :group-by ?prj, :select [?p ?o]}}}
Supported response formats for query results:
application/edn
(default)application/json
application/sparql-results+json
text/csv
orapplication/sparql-results+csv
(both SPARQL flavor w/ quoted URIs)
(support for limit
& offset
params as above)
# get query results
http :8000/queries/projects
# {:id "projects2", :count 1, :total 1, :offset 0,
# :spec {:q [{:where [[?prj "rdf:type" "foaf:Project"] [?prj ?p ?o]]}],
# :order ?p,
# :group-by ?prj,
# :select [?p ?o]},
# :body {"projects:fabric"
# [{?p "http://purl.org/dc/terms/creator", ?o "people:toxi"}
# {?p "http://schema.org/hasPart", ?o "fabric-facts"}
# {?p "http://schema.org/hasPart", ?o "fabric-core"}
# {?p "http://schema.org/hasPart", ?o "fabric-ld"}
# {?p "http://schema.org/isPartOf", ?o "projects:thing"}
# {?p "http://www.w3.org/1999/02/22-rdf-syntax-ns#type",
# ?o "http://xmlns.com/foaf/0.1/Project"}]}}
http :8000/queries/types accept:application/sparql-results+json limit==3
# {
# "head": {
# "vars": [
# "s",
# "type"
# ]
# },
# "results": {
# "bindings": [
# {
# "s": {
# "type": "uri",
# "value": "http://schema.org/mainContentOfPage"
# },
# "type": {
# "type": "uri",
# "value": "http://www.w3.org/1999/02/22-rdf-syntax-ns#Property"
# }
# },
# {
# "s": {
# "type": "uri",
# "value": "http://schema.org/SteeringPositionValue"
# },
# "type": {
# "type": "uri",
# "value": "http://www.w3.org/2000/01/rdf-schema#Class"
# }
# },
# {
# "s": {
# "type": "uri",
# "value": "http://schema.org/Attorney"
# },
# "type": {
# "type": "uri",
# "value": "http://www.w3.org/2000/01/rdf-schema#Class"
# }
# }
# ]
# }
# }
Results of registered queries can be re-transformed via optional EDN
spec (sub-set of standard query spec). Here we filter based on ?p
query var and order results by ?o
.
# get modified query results (using supplied query opts)
http :8000/queries/projects \
spec=='{:filter (= ?p "http://schema.org/hasPart") :order ?o :select ?o}'
# {:id "projects", :count 1, :total 1, :offset 0,
# :spec {:q [{:where [[?prj "rdf:type" "foaf:Project"] [?prj ?p ?o]]}],
# :group-by ?prj,
# :select [?p ?o]},
# :body {"projects:fabric" [{?o "fabric-core"}
# {?o "fabric-facts"}
# {?o "fabric-ld"}]}}}
Please see the parent project for further information.
thi.ng/fabric-ld
[thi.ng/validate "0.1.3"]
[org.clojure/data.csv "0.1.3"]
[org.clojure/data.json "0.2.6"]
[com.stuartsierra/component "0.2.3"]
[org.clojure/tools.namespace "0.2.10"]
[com.stuartsierra/dependency "0.1.1"]
[ring/ring-defaults "0.1.5"]
[ring/ring-devel "1.4.0"]
[javax.servlet/servlet-api "2.5"]
[ring/ring-mock "0.2.0"]
[compojure "1.4.0"]
[aleph "0.4.0"]
[manifold "0.1.0"]
(defproject <<project-name>> "<<conf-version()>>"
:description "Signal/Collect inspired compute graph infrastructure - fact graph module"
:url "<<conf-project-url>>"
:license {:name "Apache Software License 2.0"
:url "http://www.apache.org/licenses/LICENSE-2.0"
:distribution :repo}
:scm {:name "git"
:url "<<conf-project-url>>"}
:min-lein-vesion "2.4.0"
:dependencies [<<dep-clj>>
[thi.ng/fabric-core "<<conf-version()>>"]
[thi.ng/fabric-facts "<<conf-version()>>"]
<<dep-strf>>
<<dep-validate>>
<<dep-json>>
<<dep-csv>>
<<dep-component>>
<<dep-tools-ns>>
<<dep-depgraph>>
<<dep-ring>>
<<dep-compojure>>
<<dep-aleph>>
<<dep-manifold>>]
:profiles {:dev {:dependencies [<<dep-criterium>>
<<dep-ring-dev>>]
:global-vars {*warn-on-reflection* true}
:jvm-opts ^:replace []
:aliases {"cleantest" ["do" "clean," "test"]}}}
:pom-addition [:developers [:developer
[:name "Karsten Schmidt"]
[:url "http://postspectacular.com"]
[:timezone "0"]]])
The autogenerated namespace thi.ng.fabric.ld.version
contains a single
symbol version
holding the version string defined above:
(use '[thi.ng.fabric.ld.version])
(prn version)
; "<<conf-version()>>"
Copyright © 2015 Karsten Schmidt
This project is open source and licensed under the Apache Software License 2.0.