Recently my company went with PBworks (formerly PBwiki) to use for internal collaboration. One of my projects is building a “dashboard” web app to bring in data from different sources, and the first thing users want to see in it is the recent activity log from the wiki. Here’s how I tapped into the PBworks API and brought it into the web app, which is being built using ASP.NET MVC and jQuery.
Since I can’t display my company data, I created a demo project using the jQuery UI design & planning wiki (a great resource in itself), since it’s a public wiki. The jQuery UI wiki is already enabled for API use. If you want to enable your own wiki, go to Settings > Developer Interface. Also note your three API keys as they’ll need to be passed along depending on your security settings.
Looking through the PBworks API documentation you’ll notice that they return all data in JSON. Naturally I thought the quickest route to retrieving that data would be call it’s URLs directly using jQuery’s getJSON call.
In my ASP.NET MVC project, for now I just wanted to see the PBworks data on the default view. So I simply went to /Views/Home/Index.aspx, cleared out the default content and added a custom div tag. The plan was to populate the div tag via AJAX using jQuery. Later this might make sense to move to a PartialView.
Directly after the div tag I added javascript to fill the div with the data returned from the PBworks API call. In this case I’ll use the GetChanges call to start and do a test to see if the getJSON call even executes. Here’s the code for the MainContent section of the view:
<div id="pbWorksData">
</div>
<script type="text/javascript">
$(document).ready(function() {
$.getJSON("http://jqueryui.pbworks.com/api_v2/op/GetChanges/_type/jsontext", function(data)
{
$("#pbWorksData").append("data goes here");
});
});
</script>
Since we’re using jQuery we need to add a reference to it in the main head tag. I added mine to the master page at /Views/Shared/Site.master.
<script src="../../Scripts/jquery-1.3.2.min.js" type="text/javascript"></script>
Unfortunately this first attempt didn’t work, which confused me for a while. The same type of call works with the Flickr API using the sample code in the jQuery getJSON docs. The URL also works if you navigate to it straight. And for this public wikis you don’t need to pass any API keys in the URL.
Further inspection with the excellent Firebug add-on reveals a security error.
Turns out the PBworks folks aren’t allowing cross-domain javascript calls, even using JSONP which is supported in jQuery as of version 1.2. This was confirmed in an email to them, reasons being for security. Notice also we’re not passing in a
To get around the cross-domain issue, we’ll just access the API via server-side code in a model class using the WebRequest and WebResponse classes. In fact we’ll just pass the JSON straight to the controller with little modification.
Here’s the complete PBworks model class. Notice at the end we had to strip out some surrounding text (/* -secure- */). If you don’t do this it won’t be recognized as JSON. PBworks informed me that it was in there to prevent the hijacking of credentials over browsers, and that they’re working on an alternative method to remove the need for this extra text.
using System.IO;
using System.Net;
namespace PbApiDemo.Models
{
public class PBworks
{
public string GetChanges()
{
string url = "http://jqueryui.pbworks.com/api_v2/op/GetChanges/_type/jsontext";
WebRequest request = HttpWebRequest.Create(url);
WebResponse response = request.GetResponse();
string jsonResponse = "";
using (StreamReader sr = new StreamReader(response.GetResponseStream()))
{
jsonResponse = sr.ReadToEnd();
}
//Strip out surrounding /* -secure- */ text to keep it recognized as JSON
jsonResponse = jsonResponse.Replace("/*-secure-", "");
jsonResponse = jsonResponse.Replace("*/", "");
return jsonResponse;
}
}
}
In the controller class (PBworksController), I just created an instance of the PBworks model and passed the JSON through as text, setting the browser’s page type to application/json.
using System.Web.Mvc;
using PbApiDemo.Models;
namespace PbApiDemo.Controllers
{
public class PBworksController : Controller
{
private PBworks pbw = new PBworks();
public ActionResult GetChanges()
{
return Content(pbw.GetChanges(), "application/json");
}
}
}
Now that the correct JSON is returned from a controller in the project, back in our default view we just change the URL in the javascript code.
$(document).ready(function() {
$.getJSON("/PBworks/GetChanges", function(data)
{
$("#pbWorksData").append("data goes here");
});
});
Ran the project now and sure enough the test text inside the getJSON call shows up. Now we’re in business.
Now that I had the complete JSON object, I needed to iterate over each item returned and render them appropriately on the page. To quickly see what’s available I pasted the JSON into this cool JSON 2 HTML tool.
For use in jQuery, the parent object we’re concerned with is actually contained in the changes collection. From each item within changes, I wanted to display and link the page, author, action taken on that page, and show the lasted edited date/time. I appended all this html via jQuery doing some formatting and manipulation to get the links and date/times right. Later on we might want to move the javascript to another file and optimize it a bit, but it works for now. Here’s the final javascript contained in the default view:
<script type="text/javascript">
$(document).ready(function() {
$.getJSON("/PBworks/GetChanges", function(data)
{
//Create an unordered list to hold all the entries
$("#pbWorksData").append($("<ul/>"));
$.each(data.changes, function(i, item)
{
if (item.page != null)
{
//Get date/time from "epoch" number
var editDate = new Date(item.time * 1000);
$("#pbWorksData ul")
.append($("<li/>")
.append($("<a/>")
//Page name and link
//Replace spaces with dashes in url
.attr("href", "http://jqueryui.pbworks.com/" + item.page.replace(/ /g,"-"))
.append(item.page))
.append(" - ")
//Page "action"
.append(item.op_word)
.append(" by ")
.append($("<a/>")
//Page author and link
.attr("href", "http://jqueryui.pbworks.com/user/" + item.user_id)
.append(item.user_name))
.append(" on ")
//Last edited date
.append(editDate.toLocaleString())
);
}
});
});
});
</script>
The final rendering looks like this:
Hopefully this helps anyone else out there working with the PBworks API.
Download the demo project (requires Visual Studio 2008 and ASP.NET MVC)



Great job, but I thought I’d point out that PBworks offers many different formats for the return including XML which might be easier for you in ASP.Net. For a list of all available return types see http://pbworks.com/api_v2/#Specials under the _type parameter.
I prefer the terseness of JSON over XML, but good to know you have various formats.