Skip to content

Semantu/lincd

Repository files navigation

LINCD.js

Linked INteropeable Code & Data

All the tools you need to build Linked Data applications with ease in one package

With Linked Components you can rapidly prototype an interface powered by Linked Data.

To our knowledge, LINCD.js is the only linked data library that supports you all the way to the UI layer.

New to Linked Data? It is a W3C standard based on RDF used to build interconnected knowledge graphs. It is also known as Structured Data which can help search engines to present rich snippets in search results.

LINCD offers:

LINCD.js is compatible with the RDFJS data model

See also

Why?

LINCD is built from the ground up with a modern tech stack and integrates the latest developments. This allows us to offer advanced features that go beyond other existing RDF JavaScript libraries. Whilst also offering solutions for some major challenges in the world of Linked Data:

Making Linked Data app development easy

Graph databases are being adopted everywhere. Tons of Open Linked Data is being published. Tools have matured, but the learning curve for developers is still steep.

LINCD significantly reduces the amount of learning required and makes it much easier to work with Linked Data.

Reusable code for Linked Data

There are tons of ontologies (reusable linked data structures) available. But without a good searchable registry, it's hard to find the right one. And starting to use a specific ontology can be time-consuming still. Reusable UI components built specifically for Linked Data are virtually non-existent.

LINCD.org offers an open registry of quality ontologies and UI components built for those ontologies. Each of these ontology and components can be imported and used with just a few lines of code. This library make it easy to develop and share such ontologies and components in the registry.

Solving data validation & more

Another hurdle in the adoption of Linked Data has been the openness of the RDF model. With a lack of proper data restriction and data validation tools, maintaining a clean dataset in real life applications has been a challenge. W3C has since published SHACL, which is an excellent standard to tackle this. However, the tools to work with SHACL have been minimal.

LINCD goes full in on SHACL and places SHACL's data "Shapes" right at the center of development. This creates much simpler and cleaner code, frees developers up from thinking about which classes & properties to use and allows us to offer advanced features like automatic data loading and data validation that to our knowledge no other Linked Data library or framework offers.

Installation

npm + node.js

npm install lincd
const lincd = require("lincd");

See this tutorial on how to build linked data applications with LINCD.js

UI Components built for Linked Data

UI components run on data. In a typical development environment, the component simply takes low level data like strings,numbers and booleans as variables or 'props' (in React). The developer is usually responsible for obtaining this data from a database, and then manually providing the right data to each prop/variable of the component.

But with Linked Data we can reuse data structures. So what if we had components that consume these reusable data structures? All the developer has to do then, is to obtain data with the right structure, and hand it to the component.

That is exactly what we've made possible with LINCD!

Components consuming Shapes

LINCD introduces the concept of Linked Components. These are UI components that get linked to a specific Shape. The shape informs the structure of the data that the component expects to receive.

Here is a simple example of a functional component:

Note: Currently LINCD exclusively supports React components, though other libraries may be added in the future.

import {Person} from 'lincd-foaf/lib/shapes/Person';
export const PersonView = linkedComponent<Person>(Person, ({source}) => {
  //sourceShape is an instance of Person
  let person = source;
  //get the name of the person from the graph through the Person shape
  return <h1>Hello {person.name}!</h1>;
});

This component can then be used by providing an instance of the Person shape as it's source (using the 'of' property):

let person = new Person();
person.name = 'René';
return <PersonView of={person} />;

Linking a component (like PersonView defined above) to a specific data structure (in this case the shape Person) gives it several great benefits:

Automatic data loading

LINCD.js can connect to any number of triple stores and/or graph databases. All the data you request in your component will be automatically loaded from the right place and will be available when your component runs.

In the example above, all the data is already available locally, since the person was created right there.

But consider this example:

let person = new Person('http://www.example.com/#me');
return <PersonView of={person} />;

Here we create a Person instance for the NamedNode with URI http://www.example.com/#me. The data for this node (like the name of the person) may not be loaded yet. So LINCD will automatically query the right store for this data and only continue to render PersonView when the data is loaded

Automatic data validation

Once you have linked your component to specific shapes (data structures), LINCD.js ensures that only those nodes in the graph that match with this shape will be allowed to be used with this component. Because of this, you can rest assured that all the data will be there and in the right format.

That is, in the example above, PersonView will only render once LINCD has confirmed that the provided person instance is a valid instance of the Person shape. With the Person example later on this page, this would mean it has exactly one name defined under person.name and person.knows returns a set of valid Person instances.

Automatic re-rendering whenever the graph changes

Linked Components automatically rerender whenever their data source updates a relevant property in the graph.

Consider this example:

let person = new Person();
person.name = 'René';
setTimeOut(() => {
  person.name = 'Joe';
},1000);
return <PersonView of={person} />;

In this example, when the persons name gets updated after 1 second, PersonView will automatically rerender to update the displayed name.

Shapes

LINCD introduces Shape classes that generate SHACL Shapes.

These classes enable automatic data validation and abstract away RDF implementation details.

Consider this example shape:

Definition

@linkedShape
export class Person extends Shape {
 /**
  * indicates that instances of this shape need to have this rdf.type
  */
  static targetClass: NamedNode = foaf.Person;

 /**
  * instances of this person shape are REQUIRED to have exactly one foaf.name property
  */
  @literalProperty({
    path: foaf.name,
    required: true,
    maxCount: 1,
  })
  get name() {
    return this.getValue(foaf.name);
  }
  set name(val: string) {
    this.overwrite(foaf.name, new Literal(val));
  }

  /**
   * values of the property foaf.knows needs to be valid instances of this Person shape as well
   */
  @objectProperty({
    path: foaf.knows,
    shape: Person,
  })
  get knows(): ShapeSet<Person> {
    return Person.getSetOf(this.getAll(foaf.knows));
  }
}

Usage

Now when we use the shape above, we can simply use plain and simple object-oriented code. The code below creates RDF triples in the graph, but it does not need to know about any specific RDF properties or classes to use.

Instead, it simply uses the accessors from the Shape.

Furthermore, the shape class allows us to validate our graph. This happens automatically when visualising specific shapes from the graph with Linked Components

let person = new Person();
person.name = "Rene";

let person2 = new Person();
person2.name = "Jenny";

person.knows.add(person2);

//both persons are valid instances of Person
console.log(Person.validate(person)); //true
console.log(Person.validate(person2));//true

In-memory RDF Graph Database

With an intuitive resource-centric API:

In other RDF libraries you will have to work with raw triples / quads. Creating triples or quads or searching your graph requires you to think in terms of subject,predicate,object,graph.

However, a triple is simply a subject node that has points to (the predicate or 'edge') another node. LINCD instead lets you think of your graph as nodes (subjects) that have values (the objects) for certain properties (the predicates).

In other words, you can simply update & search your graph from any node, by setting/getting properties.

Here's some examples:

Setting properties

let person = NamedNode.getOrCreate("http://ex.org/person");
let person2 = NamedNode.getOrCreate("http://ex.org/person2");
person.set(foaf.name,new Literal("John Doe"));
person2.set(foaf.name,new Literal("Jane"));
person.set(foaf.knows,person2);

This results in the following triples

<http://ex.org/person> foaf:name "John Doe"
<http://ex.org/person> foaf:knows <http://ex.org/person2>

Searching the graph

Methods like getAll(property) and getOne(property) and getValues(property) all return sets of values. These sets in turn have the same methods, to get properties of all the nodes in the set.

For example, to obtain the names of the persons that a person knows:

//a Set of Literals
person.getAll(foaf.knows).getAll(foaf.name);

Alternatively you can also go straight to the literal value:

//["name1","name2"]..
console.log(person.getAll(foaf.knows).getValues(foaf.name));

Removing properties

To remove triples from the graph, simply unset the properties

//overwrite all previous values of a property, the person will now ONLY know person3
person.overwrite(foaf.knows,person3);

//remove 1 specific connection in the graph
person.unset(foaf.knows,person3);

//remove all connections of a certain property
property.unsetAll(foaf.knows);

A registry of reusable UI components, Shapes & ontologies

lincd.org is a registry of components, shapes and ontologies built with lincd.js. Each of these can be imported and used with a few lines. This is the best place to get started to build an application powered by linked data.

Documentation

See docs.lincd.org for the full documentation plus helpful tutorials for lincd.js

Examples

See lincd.org/examples for a list of examples with source code on github.

Contributing

To make changes to lincd.js, clone this repository and install dependencies with npm install. Then run npm run dev to start the development process which watches for source file changes in src and automatically updates the individual transpiled files in the lib and the bundles in the dist folder.

Alternatively run npm run build to build the project just once.

We welcome pull requests.

License

MPL v2