JavaScript Developers
Get started with RDF in JavaScript
In case you have little to no experience with RDF you might want to read the RDF Primer (opens new window) first, which gives a good basic introduction to the concepts of RDF. Also, trying Wikidata's Query Service (opens new window) gives you a good non-technical introduction to RDF. Further, you should know how to use NPM packages (opens new window) in your JavaScript projects.
Load RDF data into your application
One of the first things you want to do is to load existing RDF data and do some work on it in JavaScript.
Basically, we need an RDF equivalent of JSON.parse()
, but instead of JSON we load RDF from an existing resource.
We provide abstractions that allow you to load data from different sources in a similar fashion.
Load data from a file
This example loads a local RDF file and parses the data into a dataset. It can parse common RDF formats automatically.
require('tbbt-ld')
const { join, dirname } = require('path')
// node_modules/tbbt-ld/dist/tbbt.nq
const tbbt = join(dirname(require.resolve('tbbt-ld')), 'dist/tbbt.nq')
const fromFile = require('rdf-utils-fs/fromFile')
const stream = fromFile(tbbt)
stream.on('data', quad => {
console.log(`${quad.subject.value} ${quad.predicate.value} ${quad.object.value}`)
})
When you load data from a file, you will always get back a stream.
Load data from HTTP
This example loads an RDF file available on an HTTP resource and parses the data into a dataset. It can parse common RDF formats automatically.
const fetch = require('@rdfjs/fetch')
const res = await fetch('https://zazuko.github.io/tbbt-ld/dist/tbbt.nq')
const dataset = await res.dataset()
for (const quad of dataset) {
console.log(`${quad.subject.value} ${quad.predicate.value} ${quad.object.value}`)
}
Load data from SPARQL endpoint
This example is using the SPARQL 1.1 Query Language (opens new window), in particular a CONSTRUCT (opens new window) query that returns an RDF graph.
const SparqlClient = require('sparql-http-client')
const client = new SparqlClient({ endpointUrl: 'https://query.wikidata.org/sparql' })
const stream = await client.query.construct('DESCRIBE <http://www.wikidata.org/entity/Q54872>')
stream.on('data', quad => {
console.log(`${quad.subject.value} ${quad.predicate.value} ${quad.object.value}`)
})
When you load data from a SPARQL endpoint, you will always get back a stream.
Load into a dataset structure
In most cases you will want to load the data from the stream into a dataset.
As you saw above, this is only directly possible by using the fetch
function, all other functions only provide a stream interface.
To load any of these streams into a dataset, you can use the following code snippet:
const rdf = require('rdf-ext')
const SparqlClient = require('sparql-http-client')
const client = new SparqlClient({ endpointUrl: 'https://query.wikidata.org/sparql' })
const stream = await client.query.construct('DESCRIBE <http://www.wikidata.org/entity/Q54872>')
const dataset = rdf.dataset()
await dataset.import(stream)
for (const quad of dataset) {
console.log(`${quad.subject.value} ${quad.predicate.value} ${quad.object.value}`)
}
Interact on RDF Data in your application
We obviously want to do something with the data. For that we provide several libraries that facilitate interacting with RDF data in JavaScript.
Understand namespaces
RDF is heavily using the concept of IRIs (opens new window) as identifiers for things. This is very powerful and heavily used in more complex RDF based applications. However, it is not necessarily nice to work with these IRIs in code so we provide some syntactic sugar (opens new window) to improve readability of the code when working with IRIs. For that you can use the following package:
const namespace = require('@rdfjs/namespace')
const ns = {
schema: namespace('http://schema.org/'),
rdf: namespace('http://www.w3.org/1999/02/22-rdf-syntax-ns#')
}
// create given name named node
const givenName = ns.schema.givenName
const type = ns.rdf.type
console.log(`${givenName.value} (${givenName.termType})`)
console.log(`${type.value} (${type.termType})`)
Traverse an RDF graph
There are many ways to interact with triples once they are available in a dataset. There are two basic specifications that define a common interface implemented and used by multiple libraries in the JavaScript RDF world:
- RDF/JS: Data model specification (opens new window)
- RDF/JS: Dataset specification 1.0 (opens new window)
We do not recommend to start with them right away, because most of the time you do not need the kind of low-level interfaces defined by those specifications. Most of our libraries either implement these specifications or use them as a foundation.
For most interactions with RDF, you want to use an abstraction that is more graph-oriented and provides helper methods for common interactions on a graph.
For that we built the clownface
library:
const cf = require('clownface')
const fetch = require('@rdfjs/fetch')
const namespace = require('@rdfjs/namespace')
const ns = {
schema: namespace('http://schema.org/'),
rdf: namespace('http://www.w3.org/1999/02/22-rdf-syntax-ns#')
}
const dataset = await fetch('http://zazuko.github.io/tbbt-ld/dist/tbbt.nt')
.then(response => response.dataset())
const tbbt = cf({ dataset })
const stuartBloom = tbbt.namedNode('http://localhost:8080/data/person/stuart-bloom')
const peopleStuartKnows = stuartBloom
.out(ns.schema.knows)
.map((person) => {
const personalInformation = person.out([
ns.schema.givenName,
ns.schema.familyName
])
return personalInformation.values.join(' ')
})
.join(', ')
console.log(peopleStuartKnows)
Create a new graph with the clownface library
With clownface
you can also manipulate graphs and add triples to it:
const cf = require('clownface')
const rdf = require('rdf-ext')
const namespace = require('@rdfjs/namespace')
const ns = {
schema: namespace('http://schema.org/'),
rdf: namespace('http://www.w3.org/1999/02/22-rdf-syntax-ns#')
}
const zazuko = cf({ dataset: rdf.dataset() })
zazuko
.namedNode('http://example.org/zazuko')
.addOut(ns.rdf.type, ns.schema.Organisation)
.addOut(ns.rdf.name, 'Zazuko')
for (const quad of zazuko.dataset) {
console.log(`${quad.subject.value} ${quad.predicate.value} ${quad.object.value}`)
}
Persist RDF to disk or store
After you create or update data in RDF, you want to store it in some way. In this example we serialize triples into a file on the filesystem:
const { readFileSync } = require('fs')
const rdf = require('rdf-ext')
const toFile = require('rdf-utils-fs/toFile')
const namespace = require('@rdfjs/namespace')
const ns = {
ex: namespace('http://example.org/'),
schema: namespace('http://schema.org/'),
rdf: namespace('http://www.w3.org/1999/02/22-rdf-syntax-ns#')
}
const dataset = rdf.dataset()
dataset.addAll([
rdf.quad(ns.ex.zazuko, ns.rdf.type, ns.schema.Organisation),
rdf.quad(ns.ex.zazuko, ns.rdf.name, rdf.literal('Zazuko'))
])
await toFile(dataset.toStream(), 'test.ttl')
console.log(readFileSync('test.ttl').toString())
Analytics on RDF data
Run SELECT SPARQL Queries to create Tables
Whether you are consuming RDF data in your intranet or in the Linked Open Data Cloud (opens new window), you will often interact with the SPARQL protocol family.
In case you're not familiar with SPARQL, we recommend checking out Wikidata's SPARQL Tutorial (opens new window).
For any kind of interaction with SPARQL we provide a powerful library called sparql-http-client
.
This library provides a JavaScript based abstraction for easier handling of SPARQL Queries and Graph Store requests.
We use it to fetch the height of the Eiffel Tower from Wikidata:
const SparqlClient = require('sparql-http-client')
const client = new SparqlClient({ endpointUrl: 'https://query.wikidata.org/sparql' })
const stream = await client.query.select(`
PREFIX wdt: <http://www.wikidata.org/prop/direct/>
PREFIX wd: <http://www.wikidata.org/entity/>
SELECT * WHERE {
# With Q243 being the identifier for the Eiffel Tower and P2048 being the
# identifier for the height of an entity
wd:Q243 wdt:P2048 ?height .
}
`)
stream.on('data', row => {
console.log(row.height.value)
})
Fetch data through a SELECT SPARQL query to hand over to D3
For visualizing data, D3.js (opens new window) is a popular and powerful library. With d3-sparql (opens new window) we provide a library that makes it easy to wrap data from SPARQL into the commonly used JavaScript structures of d3-csv (opens new window).
In this example we cannot do a visualization due to RunKit's limitations but we can print the highest building of the world to the console:
const d3 = require('d3-sparql')
const fetch = require('isomorphic-fetch')
var wikidataUrl = 'https://query.wikidata.org/bigdata/namespace/wdq/sparql'
var skyScrapersQuery = `
PREFIX wdt: <http://www.wikidata.org/prop/direct/>
PREFIX wd: <http://www.wikidata.org/entity/>
SELECT ?item ?itemLabel (MAX(?heights) as ?height)
WHERE
{
# With P31 = "instance of", Q11303 = "skyscraper",
# Q1570262 = "unfinished building" and P2048 = "height of an entity"
?item wdt:P31 wd:Q11303.
FILTER NOT EXISTS { ?item wdt:P31 wd:Q1570262}
?item p:P2048/psn:P2048/wikibase:quantityAmount ?heights.
?item rdfs:label ?itemLabel.
FILTER(LANG(?itemLabel) = 'en')
}
GROUP BY ?item ?itemLabel
ORDER BY DESC(?height)
`
d3.sparql(wikidataUrl, skyScrapersQuery).then(function(data) {
console.log(data)
})
Further documentation, support & questions
All our libraries are released under the MIT license.
Zazuko provides commercial support for these libraries, please get in contact with us if you would like to know more.
- If you have questions, we recommend starting a topic on the rdf.community (opens new window) discussion forum, for example in the RDF Tooling / Libraries category (opens new window) category.
- If you find bugs, feel free to open an issue in the appropriate GitHub repository.
- In case you're missing some functionality or documentation is unclear, please discuss that in the discussion forum first. If it leads to new ideas we can create GitHub issues for it.
- And last but not least, pull requests are more than welcome!
This document provides a brief introduction, to dive deeper into the topics please have a look at:
- rdf-ext (opens new window) - The entry page for our RDF Interfaces Extensions provides an overview of all libraries that are currently available. This is a great starting point if you want to dive deeper and do more low-level things with RDF in JavaScript. This page links to work from many other groups and people, like the RDFJS (opens new window) effort.
- Within rdf-ext we have a documentation (opens new window) repository that provides more information about how to work with low-level interfaces.