Leveraging Client-Side API and Linked Data Support

In my post on supporting client-side consumption of linked data, I did an in depth review of the technologies necessary to support client-side use of APIs and linked data. In this blog post, we'll look at a specific demonstration example using APIs and linked data in a client-side application.

Demo Features

The demonstration example is design to show how an existing full record display screen in a discovery interface could be augmented to display additional information about a given author when a link is clicked. The demo pulls selected additional author information from VIAF, Wikidata and DBpedia. The key pieces of additional data are as follows:

  • Birthdate
  • Death date
  • Birthplace
  • Description
  • People influenced
  • People influenced by

Reading a VIAF Graph

VIAF contains the author's birthdate, death date and all the various forms of the author's name. However, to access VIAF via JavaScript, CORS support is needed. Otherwise, a proxy is needed. Because of the changes this month to VIAF, CORS is now supported and URLs can be accessed directly. So the JavaScript reads the data from VIAF, loads the graph, and then parses out the relevant data.

Request JavaScript Code

kb = $rdf.graph(); 
$http({ 
  method: 'GET', 
  url: uri + '/', 
  headers: { 
       'Accept': 'application/rdf+xml' 
     }, 
}).then(function successCallback(response) { 
    $rdf.parse(response.data, kb, uri, 'application/rdf+xml');    
    $scope.names = kb.each($rdf.sym(uri), SCHEMA('name')); 
    $scope.birthDate = kb.the($rdf.sym(uri), SCHEMA('birthDate')).value; 
    $scope.deathDate = kb.the($rdf.sym(uri), SCHEMA('deathDate')).value; 
        
  }, function errorCallback(response) { 
    console.log(response); 
  });

SPARQL of Wikidata

Wikidata has information on the author's birthplace as well as a brief description of them. The simplest way to access this data is to send a SPARQL query that finds the relevant information based on the VIAF ID. Wikidata uses the numeric VIAF ID rather than the VIAF URI. So the numeric ID has to be extracted from the URI. Then, a SPARQL query can be constructed and sent to VIAF. The query returns a JSON document, which contains the relevant data. This document is parsed and the data added to the $scope variable.

SPARQL Query

sparql_url = 'https://query.wikidata.org/sparql?query='; 
sparql_url +=    'SELECT ?birthplaceLabel ?description' + 
    ' WHERE {' +  
    ' ?author wdt:P214 "' + viafId  + '".' + 
    ' ?author schema:description ?description.' + 
    ' ?author wdt:P19 ?birthplace.' + 
    ' SERVICE wikibase:label {' + 
    ' bd:serviceParam wikibase:language "en" .' + 
    '}' + 
    ' FILTER(LANG(?description) = "en")' +  
    '}'; 
sparql_url += '&format=json';

Request JavaScript Code

$http({ 
    method: 'GET', 
    url: sparql_url 
    }).then(function successCallback(sparql_response) { 
      //parse the JSON response from the SPARQL query  
      result = angular.fromJson(sparql_response.data); 
      $scope.birthplace = result.results.bindings[0].birthplaceLabel.value; 
      $scope.description = result.results.bindings[0].description.value;       
    }, function errorCallback(response) { 
      console.log(response); 
    });

SPARQL of DBpedia

In addition to the author information from VIAF and Wikidata, I also want to incorporate some information from DBpedia into a display. In particular, I'm interested in the people who influenced the author and the people the author influenced. So I need to create a SPARQL query that returns the names for both of these types of people. I'm doing this in a single query to minimize the number of requests I have to make to the server. The request returns the given name and surname for each person. It also returns a value that indicates if they are influenced by or an influence of the author. The JavaScript code parses this data and organizes it so it is accessible within the $scope variable.

SPARQL Query in JavaScript

dbpedia_sparql_url = 'https://query.wikidata.org/sparql?query='; 
dbpedia_sparql_query = [ 
                   "SELECT ?type ?givenName ?surname", 
                   "WHERE {", 
                   "{", 
                   "?author dbp:viaf " + viafId + ".", 
                   "?s dbp:influenced ?author .", 
                   "?s foaf:givenName ?givenName .", 
                   "?s foaf:surname ?surname .", 
                   "BIND(\"influencedBy\" AS ?type).", 
                   "}", 
                   "UNION", 
                   "{", 
                   "?author dbp:viaf " + viafId + ".", 
                   "?s dbp:influences ?author .", 
                   "?s foaf:givenName ?givenName .", 
                   "?s foaf:surname ?surname .", 
                   "BIND(\"influences\" AS ?type).", 
                   "}", 
                   "}", 
                   "ORDER BY ?type", 
                   ].join(" "); 
dbpedia_sparql_url += dbpedia_sparql_query + '&format=json';

Request JavaScript Code

$http({ 
    method: 'GET', 
        url: dbpedia_sparql_url 
    }).then(function successCallback(sparql_response) { 
          //parse the JSON response from the SPARQL query  
          result = angular.fromJson(dbpedia_sparql_url_response.data); 
          influenced = []; 
          influencess = []; 
        influencedNodes = result.results.bindings 
        for (i = 0; i < influencesNodes.length; i++) { 
            if (influencesNodes.type == 'influences') { 
                influenced.push(influencesNodes.givenName + ' ' + influencedNodes.surname); 
            }else{ 
                influences.push(influencesNodes.givenName + ' ' + influencedNodes.surname); 
            } 
        } 
        $scope.influenced_persons = influenced; 
        $scope.influences_persons = influences; 
           
           
    }, function errorCallback(response) { 
      console.log(response); 
    });

Putting It All Together

Once I've gathered all the data from the various sources, I can display it on the screen. I'm using AngularJS to power this demo. The $scope variable contains all the relevant data, and the author-template.html controls how the information is displayed in a new window.

Author Template

<h2>Author Information</h2>
 
<p>Other names</p>
<ul>
    <li ng-repeat="name in names">
   Language: {{name.lang}} - {{name.value}}
    </li>
</ul>
<p>Birth date: {{birthDate}}</p>
<p>Death date: {{deathDate}}</p>
<p>Birthplace: {{birthplace}}</p>
<p>Description: {{description}}</p>
 
<p ng-show="influenced_persons">Influenced: </p>
    <ul ng-show="influenced_persons">
        <li ng-repeat="influenced_person in influenced_persons">
        {{influenced_person}}
        </li>
      </ul>   
 
<p ng-show="influences_persons">Influenced By: </p>
    <ul ng-show="influences_persons">
        <li ng-repeat="influences_person in influences_persons">
        {{influences_person}}
        </li>
      </ul>

The new window contains the author names.

file

It also includes the birthdate, death date, birthplace, description, who they influenced, and who influenced them.

file

Final Thoughts

This demonstration script shows how, when an API or linked data endpoint supports consumption by JavaScript, you can create new innovations and solve different problems. However, it doesn't address optimizations for performance or best user experience for displaying this type of information.  

User testing should be performed to assess the usability of the demo and to make usability enhancements. Additionally, there may be more efficient ways to create this type of functionality. This might be done by creating a cache locally or by reducing the number of queries via a federated SPARQL query. However, these techniques may not be practical if one wants a simple JavaScript without a backend. Further investigation would be needed to determine the most effective way to create this type of application for production use. However, creating an application that displays author information in a responsive fashion would not be possible without JavaScript in the relevant APIs and linked data. A full copy of the demo code is available via GitHub.

  • Karen Coombs

    Karen Coombs

    Senior Product Analyst