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 clientRest
- for making ajax requestsEntryInfo
- for handling the administrative information for of entriesPrototypeEntry
- for creating entriestypes
- enumeration of typesrdfjson/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 entriesUser
- user resource for handling username, homecontext etc.Group
- group resource for handling a list of user entriesGraph
- graph resource for handling RDF graphsStringResource
- for handling strings up to 1000 characters longFile
- 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:
- Load the library
- Connect to a EntryStore repository
- Authenticate yourself
- Find a suitable context
- 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 links¶
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 search 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:
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.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.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);