User talk:Conrad.Irwin/Api.js

The API wrapper edit

The JsMwApi() is a Javascript convenience wrapper around the MediaWiki API. Documentation here merely describes the wrapper, for an overview of what the API can do, read the Mediawiki Page. It evolved out of the API wrapper at the top of User:Conrad.Irwin/editor.js - as with all of my code, please feel free to fix bugs or add features as you find them or require them.

Step 1: Bind to /w/api.php edit

var localApi = JsMwApi();              // Assuming that this is inside a MediaWiki skin, localApi communicates with the local api.
var nearbyApi = JsMwApi("/w/api.php"); // If we are not inside a MediaWiki page, this allows us to connect to an api on the same hostname.
var remoteApi = JsMwApi("//en.wikipedia.org/w/api.php"); // Connect to an api.php on a remote server (with JSON callback restrictions)

The first two give you an API which is unrestricted, anything that the server will let you do can be done by the wrapper. The third option must use the JSON callback method of communication which restricts the number of operations that you can perform - see API:Data formats for more information.

NOTE: You can force JsMwApi() to pretend that a remote wiki is local by passing "local" as the second parameter to the constructor. This will only work if you are developing in an environment not restricted by the cross-domain security restrictions found in browsers.

Step 2: Making API requests edit

The value returned by JsMwApi() is a function that takes two parameters, the first is the query you wish to perform, the second is the callback that will be called when a reply has been recieved from the api:

var localApi = JsMwApi();
localApi({action: "query", prop: "info", titles: "Alphabet"}, function (res){ 
    for(var page in res.query.pages)
        alert(res.query.pages[page].title);
});

Encoding parameters edit

In general you can either pass a string or an object as the first parameter to an API call. If you pass a string, it will be sent to api.php unchanged, so you should have already encoded it correctly. If you pass an object it will be turned into a string and encoded correctly on your behalf. The following fragment makes two identical calls to the api:

var localApi = JsMwApi()
function write_me (res) { document.body.appendChild(document.createTextNode(res.query.pages["670"].title)) }
localApi("action=query&prop=info&titles=Alphabet|Betabet"), write_me)
localApi({action:"query", prop:"info", titles:["Alphabet", "Betabet"]}, write_me)

The conversion of an object is done by encoding all of its {key: value} pairs and then joining them with ampersands:

{summary: "Some text"} == "summary=some%20text"                       // strings are escaped
{summary: "Some text", minor: true} == "summary=some%20text&minor=1"  // true booleans are passed as flags
{summary: "Some text", bot: false} == "summary=some%20text"           // false booleans are dropped completely
{titles: ["one", "two"]} == {titles: "one|two"} == "titles=one%7Ctwo" // lists are joined with pipes and then encoded

NOTE: In order to facilitate the writing of extensions, the encoder will also recurse along and into arrays constructing a query string by joining all of the subqueries together. This means that in order to update a set of parameters, you can simply create a new array with the old parameters as the first element and the new parameters as the second element. A null item will be dropped, so you need never look at the parameters you are updating. See the page extension for clarification.

Step 3: Handling response edit

The callback function that you passed to the api will be called with one argument, which is either the raw result from the api or null if an error was detected.

var mistake = JsMwApi("/w/appi.php")
mistake({action:"purge", titles="Main Page"}, function (res) {
  if (res === null)
    return alert("gone wrong")
  for (var purged in res.purge)
    alert("Purged " + res.purge[purged].title)
})

Overriding the error handler edit

When an XmlHttpResponse to a local api fails, or when a response contains a top-level api error or warning (but not an error of a submodule, i.e. a failed login is a successful API query) the error handler is called. By default this just logs the error to the console (if the console exists) and calls the original callback with null, this can be overwritten in two ways. Either you create the function JsMwApi.prototype.on_error(xhr, callback, res) which overrides the default for all instances of JsMwApi() on the page; or (preferredly) you attach an error handler to an instance of JsMwApi directly. localApi.on_error = function (xhr, callback, res) {}. You can always go back to the default using delete localApi.on_error. The parameters passed into this function are the XmlHttpRequest that was used to retreive the result (or null for the remote_request), the callback function that was passed with this query, and (possibly) the object obtained by decoding the server response as JSON.

Extensions edit

You can add properties to JsMwApi() instances by attaching properties to JsMwApi.prototype, as is standard for javascript. The only extension that has been written so far is one to allow easier interaction with one particular page, but it would also be nice to have one to help with list handling.

JsMwApi().page(title) edit

This extension allows you to interact with one particular page on a Wiki. It provides an API wrapper that sets the titles= and title= parameters automatically, so you can do things like:

var localApi = JsMwApi()
var mainPage = localApi.page("Main Page")
mainPage({action: "query", prop: "info"}, function (res) { console.log(res) })

The main advantage to using the wrapper is for the functions that it in turn provides:

.edit() edit

The edit function wraps the complication of dealing with tokens, it can either be called as JsMwApi().page("Main Page").edit(edit_callback) or JsMwApi().page("Main Page").edit(optional_parameters, edit_callback)

The optional parameters are passed onto the api call, and the edit_callback is later called with three arguments:

  1. The current text of the page
  2. A save_function
  3. The raw api result.

The save_function accepts three parameters,

  1. The new text to save
  2. The extra options for this edit (optional), for example: {summary: "Test edit", minor: true}
  3. The callback to be notified when the page save is complete (compulsary).

For example:

var sandbox = JsMwApi().page("Wiktionary:Sandbox")
sandbox.edit( function (text, save_function, edit_res)
{
    text += "Hello world from JsMwApi()"
    save_function(text, {summary: "Testing JsMwApi", minor: true}, function (save_res) 
    {
        alert(save_res ? "Saved!" : "Not Saved")
    }
});

If you prefer a less-nested style of programming, you can declare the functions in advance:

function edit_function(text, save_function, edit_res)
{
    save_function(text + "Hello world from JsMwApi()", {summary: "Testing JsMwApi", minor: true}, post_save_function)
}
function post_save_function(save_res)
{
    alert(save_res ? "Saved!" : "Not Saved")
}
JsMwApi().page("Wiktionary:Sandbox").edit(edit_function)

.parse() edit

Much simpler than the edit function, this function can be called as JsMwApi().page("test").parse(callback) or JsMwApi().page("test").parse(wikitext, callback). In the first case, the callback will be called with parsed wikitext of the page "test", and in the second it will be called with the wikitext specified parsed with "test" as the title. In both cases the second parameter passed to the callback is the original result from the api.

.parseFragment() edit

This exists so that you can parse tiny fragments without MediaWiki wrapping them in <p> </p> tags. It will only work if you pass a small, correctly formed, inline fragment of HTML. Unlike .parse(), the wikitext parameter is compulsary.

Return to the user page of "Conrad.Irwin/Api.js".