Page MenuHomePhabricator

API discovery information: add RSD link in page <head>
Closed, ResolvedPublic


One of the things I've noticed after spending some more time working with non-MediaWiki systems is that we don't always have machine-accessible information within our web pages. A fair amount of data is available in the global JS vars, but that's not trivial to read from an application that's not running in the browser.

Given the URL to some MediaWiki page -- say -- we really should be able to do at least two key things:

  1. Get the API root URL
  2. Get the wiki page title for the current page (should be treated under a separate bug if details needed)

*If* we can reliably pull the JS vars, we could reconstruct the API root as wgServer + wgScriptPath + 'api' + wgScriptExtension, but honestly I wouldn't want to have to rely on that, as the data structuring isn't very standardized.

I'd recommend using the RSD "Real Simple Discovery" system, which both WordPress and StatusNet are using to expose their WordPress and Twitter API URLs:

Here's an example on StatusNet... pages contain a discovery link:

<link rel="EditURI" type="application/rsd+xml" href=""/>

Which points to a document like this:

<?xml version="1.0" encoding="UTF-8"?>
<rsd version="1.0" xmlns="">

 <api name="Twitter" preferred="true" apiLink="" blogID="">
   <setting name="OAuth">true</setting>


So for MediaWiki we could output something like this:

<?xml version="1.0" encoding="UTF-8"?>
<rsd version="1.0" xmlns="">

 <api name="MediaWiki" preferred="true" apiLink="" blogID="">
   <!-- We could in theory expose some info like authentication -->
   <!-- support here, or leave it for meta=siteinfo -->
   <setting name="OAuth">false</setting>


This should be pluggable, so extensions that add their own machine APIs can register themselves in there. (For instance a blogging extension could provide a WordPress-compatible API.)

Version: unspecified
Severity: enhancement



Event Timeline

bzimport raised the priority of this task from to Medium.Nov 21 2014, 11:14 PM
bzimport set Reference to bz25648.

Bryan.TongMinh wrote:

Since rsd.xml needs to be different for each domain, I think it can be best generated by api.php?action=rsd. Is there any problem if the entry point is not called rsd.xml?

Looks cool.

On a similar note, it'd be nice to get the XML Schema (bug 14025)

One would presume/hope, that as long as the type and rel is the same, it could point whereever...
<link rel="EditURI" type="application/rsd+xml"

Yeah, the URL shouldn't matter here. API probably is a good place to put it, plus I like the irony of exposing the discovery for the API in the API. ;)

(In reply to comment #3)

Yeah, the URL shouldn't matter here. API probably is a good place to put it,
plus I like the irony of exposing the discovery for the API in the API. ;)

Yay, recursion! :D

Bryan.TongMinh wrote:


ApiRsd patch.

Didn't feel like digging through our skin system how to add the <link> element, so that still needs to be done. Feel free to commit, I may or may not have time to work further on this.

attachment patch.txt ignored as obsolete

Awesome, I'll take a peek over it.

Created attachment 7759
Tweaked ApiRSD patch

I've done a little testing and enhanced the patch a bit:

  • added the <link> to page header
  • tweaked the XML output to fix some attribute vs child-element oddities
  • tweaked the hook point so we can hand a slightly simpler array to extensions to use.

This looks about right to me (though I wanna double-check in a bit), and I can add some sample extension API info like so:

$wgHooks['ApiRsdServiceApis'][] = 'barfo';
function barfo(&$apis) {
$apis['Atom'] = array(

		'apiLink' => wfAppendQuery(wfScript('api'), array('action' => 'atompub')),

$apis['Twitter'] = array(

		'apiLink' => wfAppendQuery(wfScript('api'), array('action' => 'twitapi')),
		'docs' => '',
		'settings' => array(
			'OAuth' => false,

return true;

Things to double-check:

  • confirm all is well with it served as generic application/xml (should be fine)
  • double-check if we're required to make URLs fully-qualified (in which case it wouldn't hurt to enforce it on extension-provided URLs)
  • test: throw in WordPress and Twitter API points as in the ext example above, and make sure that WordPress and StatusNet Android/iPhone clients actually pick them up when given the wiki's base URL.

May need to add hook doc entry.


So far so good :D

I can confirm that StatusNet Mobile can do discovery from our RSD if I manually add Twitter API info. YAY

WordPress for iPhone 1.x fetches the RSD data but decides it's unsupported (haven't totally worked that out) while WordPress for iPhone 2.x apparently doesn't actually do RSD and looks for some hardcoded URL subpaths. :(

matthew.britton wrote:

  1. Get the API root URL

Glad to see I wasn't the only one having trouble with this. Wasn't so hard to parse out the JS variables myself... until ResourceLoader showed up and suddenly those were buried in a separate file, served from somewhere else.

This adds a third thing to look for, but eventually one day will make things easier. :)