Skip to content

JavaScript client library EntryStore.js

To interact with EntryStore from the outside it is recommended to use the dedicated javascript library - EntryStore.js. EntryStore.js simplifies communication with the EntryStore repository's REST API.

The library

The latest stable build of EntryStore.js is available at entrystore.org/js/stable/doc.

Documentation

We strive to have everything in the library documented according to the principles of jsdoc3. Hence, the jsdoc generated documentation should be considered the complete reference to the library.

For further details you can also look at the codebase of the library at Bitbucket.

Below follows a short introduction to how to get started in creating entries, changing metadata, uploading filets etc.:

Basics

At the core of the API are 4 classes:

Class Description
EntryStore The starting point of the API used to connect to the EntryStore repository, authenticate the user, create and load entries, initiate searches, maintains the cache and rest modules as well as a range of utility methods. It also provides factory methods for creating contexts, users and groups.
Entry The Entry class holds together one or several metadata graphs, potentially a resource, and administrative information (in the EntryInformation class). It also holds a range of convenience methods in the form is* and can*, e.g. isLink and canReadMetadata.
Context Contexts are containers for entries and therefore provides factory methods for creating new entries, e.g. newLink, newList etc.
SolrQuery The solr query provides a means for searching for entries. A SolrQuery instance is created via the newSolrQuery method on an EntryStore instance and by calling list() on it you get a SearchList instance. The SearchList allows you to either access entries in a paginated manner or access them all via the forEach method.

The other (most important) classes to be considered are:

  • Cache - for caching in the client
  • Rest - for making ajax requests
  • EntryInfo - for handling the administrative information for of entries
  • PrototypeEntry - for creating entries
  • types - enumeration of types
  • rdfjson/Graph - API for working with various metadata graphs (RDF)
  • Resource - the superclass of all kind of resources:
    • List - list resource for containing a list of other entries
    • User - user resource for handling username, homecontext etc.
    • Group - group resource for handling a list of user entries
    • Graph - graph resource for handling RDF graphs
    • StringResource - for handling strings up to 1000 characters long
    • File - for handling arbritary content, e.g. strings longer than 1000 characters (not an exact limit)

(The class Context is also a subclass of Resource but has already been mentioned above.)

Creating an entry

Conceptually, to create an entry you need to:

  1. Load the library
  2. Connect to a EntryStore repository
  3. Authenticate yourself
  4. Find a suitable context
  5. Create the entry in the context

Here is an example html-page that shows how it is done in a browser context.

<html><body>
    <script src="dist/entrystore.js"></script> <!-- step 1 -->
    <script type="text/javascript">
      var es = new Entrystore.EntryStore();  //Step 2
      es.auth({user: "some_user", password: "some_password"}).then(function() {  //Step 3
         var c = es.getContextById("1"); //Step 4
         c.newEntry().commit().then(function(entry) { //Step 5
            //Do something with the created entry
         });
      });
    </script>
</body></html>

Note 1: in this example we rely on the default repository location window.location.origin + "/store/" (which assumes we are running the code in a browser context).

Note 2: the entry we created in this example can hold metadata and hold a resource, e.g. in the form of an uploaded file. See the chapters about metadata and uploading files below.

Creating a link closely resembles the example above where we just created an entry with default characteristics. We just ask the context to provide us with a link context.newLink with the link target as parameter. Lets see the whole example from above again:

var es = new Entrystore.EntryStore();  //Step 1
es.auth({user: "some_user", password: "some_password"}).then(function() {  //Step 2
    var c = es.getContextById("1"); //Step 3
    c.newLink("http://slashdot.org").commit().then(function(entry) { //Step 4
       //Do something with the created link
    });
});

Creating different kind of entries

At the most fundamental level all entrys are created via the createEntry method on EntryStore by providing a PrototypeEntry instance. You can construct a PrototypeEntry yourself and set the characteristics of the future entry by calling a range of different chainable set methods. You must always provide the context wherein to create the entry, all other characteristics have default values. To create the entry you either call the createEntry method or use the shorthand commit method on the PrototypeEntry itself, e.g.:

//Assuming we have access to PrototypeEntry class and types module (loaded via require).
//Also assuming we have already authenticated and a context is available in the c variable.
new Entrystore.PrototypeEntry(c).setGraphType(types.GT_LIST).commit().then(function(entry) {
    //Do something with the created list.
});

However, to make the process of creating entries easier, there is a range of convenience factory methods available on the Context and EntryStore classes. All of these methods provide a PrototypeEntry that are ready to call commit on directly (however nothing prevents you from providing further information via some set method before calling commit). Using this approach the example above can now be made a bit easier to read:

//Assuming we have already authenticated and a context is available in the c variable.
c.newList().commit().then(function(entry) {
    //Do something with the created list.
});

The following convenience factory methods are available:

factory method characteristics of the future entry
EntryStore#newContext A context entry created in the _contexts context.
EntryStore#newUser A user entry created in the _principals context.
EntryStore#newGroup A group entry created in the _principals context.
Context#newEntry An entry that has a local information resource, e.g. allows the resource to be an uploaded file.
Context#newList An entry that contains a list of other entries.
Context#newString An entry where the resource is a string.
Context#newGraph An entry where the resource is a graph.
Context#newNamedEntry An entry where the resource has no digital representation, only metadata, e.g. a concept.
Context#newLink An entry where the resource is exeternal, i.e. not maintained in the current repository. A target URL has to be provided
Context#newRef An entry where the resource and the metadata is external, e.g. not maintained in the current repository. Two URLs have to be provided, one for the resource and one for the metadata.
Context#newLinkRef An entry where the resource is external while there are two sets of metadata, one external and one local. Two URLs have to be provided, one for the resource and one for the metadata.

Working with local metadata

Working with metadata is straightforward using the methods getMetadata, setMetadata and commitMetadata on the Entry class. Lets first add a title (using the Dublin Core property title) in the metadata on an entry (variable e) and push the updated metadata to the repository:

var md = e.getMetadata();
md.add(e.getResourceURI(), "http://purl.org/dc/terms/title", {type: "literal", value: "New title"});
e.commitMetadata().then(function() {
   //Do something when metadata has been pushed to repository.
});

You can add, modify, and remove statements from the metadata graph according to the rdfjson/Graph API. For instance, below is an example where an existing statement is modified:

var md = e.getMetadata();
var stmts = md.find(entry.getResourceURI(), "http://purl.org/dc/terms/title");
stmts[0].setValue("Modified title");

In the following example code all title statements are removed from the graph (alternatively you can remove individual statements via the Graph.remove(statement) method):

var md = e.getMetadata();
md.findAndRemove(e.getResourceURI(), "http://purl.org/dc/terms/title");

Working with cached external metadata

Per definition external metadata is not handled within the repository (it is external), however it is possible to control the cached external metadata. The methods for manipulating the cached external metadata are very similar to the methods for manipulating the regular metadata. I.e. the methods are getCachedExternalMetadata, setCachedExternalMetadata and commitCachedExternalMetadata on the Entry class. The code example below updates the cached external metadata to be in sync with the external metadata via the EntryStores own metadata proxy:

es.loadViaProxy(e.getExternalMetadataURI()).then(function(md) {
    e.setCachedExternalMetadata(md);
    e.commitCachedExternalMetadata().then(function() {
        //Do something upon success
    });
});

The proxy does support a few simple metadata conversions, see documentation, largely to help in converting between different RDF formats, but, the proxy also support RDFa, extraction of simple metadata from HTML, and the more specific Europeana and LOM/XML formats.

Note: there is yet no automatic treatment of cached external metadata in the repository, i.e. it is not updated automatically or downloaded upon creation. This may change in the future.

Working with Lists

The terminology is that a list resource belonging to a list entry. In the code example below we fetch the first page of entries for this list (the default page size is 20 entries).

var list = listEntry.getResource(true); // (*)
list.getEntries(0).then(function(entries) {
   //Do something with the members (entries) of the list.
});

(*) List resources are always available from its corresponding list entry (this is true for Lists, Groups, Contexts and FileResources), hence we can ask for it synchronously (by providing the parameter true to the getResource method). For other resources (like User, StringResource and RDFGraph) the asynchronous variant of the method has to be used that returns a promise.

If you want you can change the page size and sorting order of the list, for example:

var list = listEntry.getResource(true);
list.setLimit(50);
list.setSort({sortBy: "modified", prio: "List", descending: true});
list.getEntries(2).then(function(entries) {
   // Do something with page 2 of the members (50 per page) of the list 
   // sorted according to modified date, oldest first and 
   // entries that are List entries are at the end.
});

There is a shortcut method on the EntryStore class for asking for children of a list:

es.getListEntries(entryURI, {sortBy: "modified"}, 50, 2).then(function(entries) {
   //Do something with array of max 50 entries on page 2 sorted by modified date.
});

Uploading Files

Direct access to the file-system from javascript is not allowed in a browser setting. However, it is possible to create regular HTML input tags that allows the user to trigger a file selection dialog, e.g.:

<input id="inp1" type="file" name="uploadFile"/>

This input tag can then be used to trigger an upload of the selected file in javascript, e.g.:

c.newEntry().commit().then(function(entry) {
  var fr = entry.getResource(true);
  var nodeRef = document.getElementById("inp1");
  fr.putFile(nodeRef).then(function() {
     //Do something after file has been uploaded to the repository.
  });
});

In some cases the data to be stored in the repository can be constructed in javascript, e.g. as JSON:

fr.putJSON({attr1: "some data"}).then(...);

Or as a text:

fr.putText("A text of some sort.").then(...);

In general you can provide an explicit mimetype for the content, e.g. for storing HTML:

fr.put("<html><body><h1>An html document</h1></body></html>", "text/html").then(...);

Performing searches

EntryStore provides search via SPARQL and solr. You search by creating a searchList from where results can be retrieved in a paginated manner. A SearchList is created from a SolrQuery object. The following example uses solr to contruct a query matching links with a title containing the term "organic":

var queryObj = es.newSolrQuery().title("organic").entryType(types.ET_LINK)
  .list().getEntries(0).then(function(entries) {
    //Do something with the first page of search results (array of entries).
});

See query documentation as well as the javascript documentation for solr for more information.

Checking and changing Access

To work with the access control is in general a complicated task since the access is given by setting an access control list on an individual entry. If the access control is not explicitly set the access control set for the surrounding context is inherited.

Note: setting access control on an entry overrides the surrounding contexts access control defaults. There is one exception, the owners of the context have always full rights to all entries within the context.

To simplify there are a few common checks you can do:

  1. store.Entry.isPublic tells whether something of the entry, resource or metadata, is accessible for the guest user. I.e. anyone who has not yet authenticated themselves.
  2. store.Entry.isPrivateTo tells wheather a specific entry is private to a specified user. Note that this takes into account who the owner(s) of the surrounding context is.
  3. store.EntryInfo.hasACL tells whether the entry has an explicit access control list set that overrides the surrounding context.

Let's se an example where we give_guest the rights to read the metadata and set the principal 34 as the owner:

var ei = entry.getEntryInfo();
ei.setACL({mread: ["_guest"], admin: ["34"]});
ei.commit().then(function() {
  //Do something after the new access control have been saved to the repository.
});

Conversely, to get the entry identifier out again:

//If we continue on the above example the return value will be: {mread: ["_guest"), admin: ["34"]} 
entry.getEntryInfo().getACL(true);