XWiki JSON Web Service kick start

This tutorial addresses the development of a small Web Service in XWiki, that returns data formated in the JSON format. Our service will offer a timeline of last X edited documents on the wiki on which it runs, returning for each document the date and author of last edit.

Data format

Here is a sample of two rows to illustrate how we will format our data, using a JSON representation


{"returneddocs": 2,
  "docs": [
    {"fullName" : "Music.RageOverTheLostPenny",
      "url" : "http://www.domain.tld/xwiki/bin/view/Music/RageOverTheLostPenny",
      "author" : "XWiki.LudwigVonBeethoven",
      "date" : "2008-07-24 16:13:06.0",
      "comment": "Corrected wrong info about the story of this piece of music of mine"
    },
   
    {"fullName" : "Movies.ScienceOfSleep",
      "url" : "http://www.xwiki.org/xwiki/bin/view/Movies/ScienceOfSleep",
      "author" : "XWiki.JohnDoe",
      "date" : "2008-07-24 16:09:06.0",
      "comment": "Added a new image"  
    }  
  ]
}

The Web Service

Our web service will be held in a wiki page : Main.WebService, that would become queryable by any http client. It is written in Velocity. If you need a particular inquiry that the searchdocuments do not fit your ncessity, so you need re write the code below in Groovy.

{{velocity}}
$response.setContentType("application/x-json")
##limit default
#set ($limit = 5)
#if($request.limit)
  #set ($limit = $util.parseInt($request.limit))
#end
#set($hql = "where doc.name != null order by doc.date desc")
#set($documents= $xwiki.searchDocuments($hql, $limit, 0))
{"nbarticles": $limit ,
 "documents": [
#set ($i = 0)
#foreach($item in $documents)
#set ($i = $i+1)
#set ($recentDoc = $xwiki.getDocument($item).getTranslatedDocument())
    {"fullName": "$recentDoc.fullName",
    "url": "$recentDoc.getExternalURL("view",$recentDoc.context)",
    "author": "$recentDoc.contentAuthor",
    "date": "$recentDoc.date",
    "comment": "$recentDoc.comment"
  }#if($i != $limit)
,
#end
#end
]
}
{{/velocity}}

PoC client in XWiki

Now our Web Service is available for any http client. Usually Web Services are a great deal for different applications to exchange data, but they can also be used within the same application. For illustration purpose, we will present a small javascript client in a wiki page that regularly queries the service with an AJAX request, and evaluate and inject in the DOM the returned JSON result to offer a small "live-monitoring" table of editions on the wiki. In a real-world usage, the client could for example be a different application of the information system, that would need to be aware of the latest edition in a wiki.

Version 1, without using skin extension

Code


{{velocity}}
{{html}}
10 Last edited documents
<table id="lastestedits" class="wiki-table">
<thead id="tableheader">
  <tr>
    <td>document</td>
    <td>author</td>
    <td>date</td>
    <td>comment</td>
  </tr>
</thead>
</table>
<script type="text/javascript">

// <[!CDATA[[
function monitorWikiDocsEdition()
{
   window.setTimeout('monitorWikiDocsEdition()', 5000); // Timeout to keep looping over the service every 5 seconds.
  new Ajax.Request(
     // Here we make the asynchronous call to our previously created web service.
     // Note that we are using the XWiki API from velocity to compute the exact URL we want to hit.
     // This is possible since the entire page will be evaluated by the velocity engine before being sent to
     // the client from which this javascript function will be executed.
     // We precise the number of entries we want to retrieve using the limit parameter. The second parameter,
     // "outputSyntax" is mandatory.If we forget this parameter, we will not receive a valid JSON
     // and our client will not work.
     "$xwiki.getURL('Main.WebService', 'get', $escapetool.url({'outputSyntax': 'plain','limit': 10}))",{
       method: 'get',
        onSuccess: function(transport) {
          // first, we evaluate the JSON result to make it manipulable as javascript objects
          var res = eval( '(' + transport.responseText + ')' );
          // then we iterate over the returned elements, and inject them dynamically in the table
          for(var i = 0 ;i <res.documents.length;i++) {
             doc = res.documents[i];
             var tdDoc = new Element('td').update(doc.fullName);
             var tdAuthor = new Element('td').update(doc.author);
             var tdDate = new Element('td').update(doc.date);
             var tdComment = new Element('td').update(doc.comment);
             var tr = new Element('tr', {'id' : doc.fullName});
             tr.appendChild(tdDoc);
             tr.appendChild(tdAuthor);
             tr.appendChild(tdDate);
             tr.appendChild(tdComment);
             // if this document already exist in the table, we remove it
             if($(doc.fullName))
               $(doc.fullName).remove();
             // if the table is already full, we remove its last row
             if($('lastestedits').getElementsBySelector("tr")[10])
               $('lastestedits').getElementsBySelector("tr")[10].remove();
             // finally, we inject the row on top of the table
             new Insertion.After('tableheader', tr);
          }
       }
     }
  );
}
monitorWikiDocsEdition();
//  ]>
</script>
{{/html}}
{{/velocity}}

Result

As a result, we will have a table presenting last 10 editions on the wiki, and that updates live when new editions does occur :

MonitoringTableResult.png

Version 2, using SX

Create a page, for example. Main.ClientWebService

Add a object XWiki.JavaScriptExtension
Input the following code:


function monitorWikiDocsEdition()
{
   window.setTimeout('monitorWikiDocsEdition()', 5000); // Timeout to keep looping over the service every 5 seconds.
  new Ajax.Request(
     // Here we make the asynchronous call to our previously created web service.
     // Note that we are using the XWiki API from velocity to compute the exact URL we want to hit.
     // This is possible since the entire page will be evaluated by the velocity engine before being sent to
     // the client from which this javascript function will be executed.
     // We precise the number of entries we want to retrieve using the limit parameter. The second parameter,
     // "outputSyntax" is mandatory.If we forget this parameter, we will not receive a valid JSON
     // and our client will not work.
     "$xwiki.getURL('Main.WebService', 'get', $escapetool.url({'outputSyntax': 'plain','limit': 10}))",{
       method: 'get',
        onSuccess: function(transport) {
          // first, we evaluate the JSON result to make it manipulable as javascript objects
          var res = eval( '(' + transport.responseText + ')' );
          // then we iterate over the returned elements, and inject them dynamically in the table
          for(var i = 0 ;i <res.documents.length;i++) {
              doc = res.documents[i];
              var tdDoc = new Element('td').update(doc.fullName);
              var tdAuthor = new Element('td').update(doc.author);
              var tdDate = new Element('td').update(doc.date);
              var tdComment = new Element('td').update(doc.comment);
              var tr = new Element('tr', {'id' : doc.fullName});
              tr.appendChild(tdDoc);
              tr.appendChild(tdAuthor);
              tr.appendChild(tdDate);
              tr.appendChild(tdComment);
              // if this document already exist in the table, we remove it
              if($(doc.fullName))
                $(doc.fullName).remove();
              // if the table is already full, we remove its last row
              if($('lastestedits').getElementsBySelector("tr")[10])
                $('lastestedits').getElementsBySelector("tr")[10].remove();
              // finally, we inject the row on top of the table
              new Insertion.After('tableheader', tr);
           }
        }
      }
   );
}

monitorWikiDocsEdition();

Parameters of the java script extension:
On Demand
Parse: Yes
Cache: default

In other page, for exameple, Main.ClientPageWebService, input the following code:


{{velocity}}
{{html}}
10 Last edited documents
<table id="lastestedits" class="wiki-table">
<thead id="tableheader">
  <tr>
    <td>document</td>
    <td>author</td>
    <td>date</td>
    <td>comment</td>
  </tr>
</thead>
</table>
<script type="text/javascript">

$xwiki.jsx.use("Main.ClientWebService")

{{/html}}
{{/velocity}}

 Tcha nam! 
You have a nice webservice in your XWiki!

Tags:
Created by JeromeVelociter on 2008/07/24 10:55
   

Get Connected