API-Aktionen mit JavaScript


Auf dieser Seite wird dargestellt, wie sich API-Abfragen sowie Manipulationen mit JavaScript programmieren lassen.

Einen Einstieg zur API („Programmierschnittstelle“) für MediaWiki gibt Datenbank/API.

Überblick Bearbeiten

Die grundlegende Technologie ist Ajax.

Dort steht das „A“ für ‚asynchron‘ – das bedeutet, dass die Aktion nur angestoßen wird. Sie läuft unabhängig im Hintergrund ab. Sofort nach dem Start wird mit der nächstfolgenden JavaScript-Anweisung fortgesetzt. In der Regel wünscht man, dass die ausgeführte Funktion wieder Kontakt mit dem auslösenden Skript aufnimmt; zumindest, um zu melden, ob die Aktion erfolgreich oder nicht ausgeführt wurde. Dies ist ausschließlich über eine Callback-Funktion möglich.

Primär ist nur der Kontakt mit derselben Domain möglich, von deren HTML-Seite im Browser das Skript gestartet wurde. Auf Wiki-Seiten sind jedoch Mechanismen aktiviert, mittels derer auch mit einem anderen Projekt kommuniziert werden kann; zumindest von einer anderen Wikipedia oder von Commons Daten abgerufen werden können.

Abfragen und Aktionen Bearbeiten

Einfache Fragen nach öffentlich zugänglichen Informationen sind mit HTTP-GET möglich. Diese Fragen (query) kann im Prinzip jeder Teilnehmer im Internet stellen.

Aktivitäten, die in irgendeiner Weise das Projekt verändern, sind sicherheitsrelevant und lassen sich ausschließlich mit HTTP-POST übermitteln; dies geht nicht mehr über eine einfache URL. Zur Verifizierung ist ein „Token“ erforderlich, der zuvor in der Arbeitsumgebung des Benutzers beschafft werden muss.[1] Zu den Aktivitäten gehören:

  • Schreiben von Seiten-Inhalten (edit csrf)
  • Veränderungen der Beobachtungsliste (watch)
  • E-Mail verschicken
  • Administrator-Funktionen (Seitenlöschung, Benutzersperrung usw.)

Bis 2015 waren für die nachstehenden Aktionen einzelne Tokens erforderlich gewesen: edit, move, options, email sowie für Admins delete, protect, block, unblock, import. Inzwischen ist stattdessen einheitlich csrf (Cross-Site-Request-Forgery) zu benutzen.

Auch in eine einfache Abfrage gehen über HTTP immer Informationen über das zurzeit angemeldete Benutzerkonto ein, wenn sie aus einer Wiki-Seite heraus erfolgt; sie werden den Anmelde-Cookies entnommen: action=query&meta=tokens.

JSON Bearbeiten

Für die Nutzung der API mit JavaScript empfiehlt sich durchgängig das JSON-Format; sowohl für Anfragen wie auch für die Interpretation der Antwort.

Die Abfrage (HTTP-GET) mit einer URL stimmt exakt überein mit der Übermittlung eines JS-Objekts, das die gleichen Parameterzuweisungen enthält.

jQuery Bearbeiten

In allen Seiten von MediaWiki steht auch die Skriptbibliothek jQuery zur Verfügung. Sie vereinfacht das Arbeiten stark, indem eine Reihe von Basisfunktionen passend zum aktuellen Browser verfügbar gemacht werden. Diese werden auch laufend den Neuentwicklungen der Browser angepasst und können je nach deren Fähigkeiten geeignete Details festlegen, um eine möglichst effiziente Abarbeitung zu sichern.

Allerdings empfiehlt es sich, die Unterstützung durch das mw-Objekt in Anspruch zu nehmen, das die Handhabung weiter vereinfacht.

Vereinbarung von Callback-Funktionen Bearbeiten

Die folgenden Funktionen können auf die Abfrage-Instanz angewendet werden:

.done(fine)
Definiere fine als Funktion, die bei erfolgreicher Ausführung aufgerufen wird. Es kann auch ein Array von Funktionen angeben werden; sogar null.
  • fine(data, textStatus, jqXHR)
    • data sind die erfragten Nutzdaten (JSON-Objekt).
.fail(fault)
Definiere fault als Funktion, die im Fehlerfall aufgerufen wird. Es kann auch ein Array von Funktionen angeben werden; sogar null.
  • fault(jqXHR, textStatus, errorThrown)
.always(facility)
Definiere facility als Funktion, die immer aufgerufen wird (nach einer Antwort); sie erhält komplexe Informationen über Erfolg oder Misserfolg.
.then(facility)
Definiere facility als Funktion, die immer sofort aufgerufen wird (auch bereits vor Eintreffen einer Antwort); sie erhält komplexe Informationen über Erfolg oder Misserfolg, falls bereits eine Antwort vorliegt.

Sowohl die mittels .done() wie auch mittels .fail() vereinbarte Funktion bieten zwei Parameterwerte, die bei Bedarf ausgewertet werden können:

  • jqXHR gibt Details zum XMLHttpRequest an.
  • textStatus ist eine Zeichenkette, die in Fehlermeldungen und Protokollen vermerkt werden kann.

Technisch gesprochen geben die verschiedenen Abfrage-Funktionen ein Objekt vom Typ jQuery.Promise zurück, das es erlaubt, beliebig viele Rückruf-Funktionen zu registrieren. Sollte man mit der Registrierung einer solchen Callback-Funktion zu spät kommen und das erwartete Ereignis bereits geschehen sein, wird trotzdem sofort zurückgerufen.

mw-Objekt Bearbeiten

In allen Seiten unter MediaWiki ist das mw-Objekt vorhanden. Hier lässt sich ein besonderes Modul bereitstellen, das vereinfachte API-Abfragen unterstützt.

  • Diese API-Kommunikation muss erst mittels .loader geladen werden; Modul: mediawiki.api (Es könnte sein, dass es bereits vorhanden ist, weil ein anderes Skript es schon benutzt hatte; aber davon darf nicht ausgegangen werden.)
  • Die Programmierung in diesem Modul verwendet soweit möglich Funktionen aus jQuery und versieht sie mit Routine-Informationen zur Wiki-Anwendung.
  • Quellcodes: resources/src/mediawiki/api.js

mw.Api Bearbeiten

.Api(defaults)
Konstruiert ein neues API-Objekt, etwa: a= new mw.Api(); oder a = new mw.Api(defaults);.
Die Klasse mw.Api vereinfacht das Arbeiten insofern, als standardmäßig fünf Werte intern vorbelegt sind. Diese und beliebige andere können umdefiniert werden:
defaults.parameters .action 'query' API-Aktion, auch 'edit', 'watch' und viele andere möglich.
.format 'json' Anfrageformat
defaults.ajax .url mw.util.wikiScript('api') /w/api.php
String, aber auch mw.Uri
.dataType 'json' Antwort des Servers (MIME etc.) formatieren
.timeout 30000 30 Sekunden

Danach sind für a folgende Funktionen verfügbar:

.abort()
Abbruch aller noch nicht beendeten Anfragen für dieses Objekt.
.ajax(pars, opts)
Frei konfigurierbare Abfrage; sollte nicht direkt benutzt werden.
.get(pars, opts)
Abfrage mit GET-Methode starten.
Gibt ein Objekt vom Typ jQuery.Promise zurück, auf das Callback-Vereinbarungen angewendet werden können.
.getToken(tokenType)
Stelle einen Token bereit.
.normalizeAjaxOptions()
(eher intern benutzt)
.post(pars, opts)
Abfrage mit POST-Methode starten.
Gibt ein Objekt vom Typ jQuery.Promise zurück, auf das Callback-Vereinbarungen angewendet werden können.
.postWithToken(tokenType, pars, opts)
Abfrage mit POST-Methode starten, dabei automatisch für erforderlichen Token sorgen.
  • pars – Objekt mit aktuellen Parametern der Abfrage: Was soll abgefragt werden?
    • Konkrete Angaben sind notwendig.
    • Die Parameter sind gerade die, die in den Wiki-Dokumentationen zur API beschrieben sind. pars ist in erster Näherung die Umsetzung des Query-String in ein JavaScript-Objekt.
    • defaults.parameters ermöglicht Vorgabewerte.
  • opts – Objekt mit Ajax-Optionen: Wie soll abgefragt werden?
    • Früher war die Angabe von opts zwingend notwendig. Mittlerweile ist dieser Parameter optional. Wenn opts angegeben wird, darf es nicht null sein.
      • opts.url – Optional; Standard: Vorgabe bei new mw.Api()
      • In opts.ok war früher die Erfolgsfunktion zu vereinbaren. Das ist inzwischen nachträglich zuzuweisen.
        • Es war früher eine Kurzform möglich: Erfolgsfunktion function als optsopts.ok
      • Genauso war als opts.err die Funktion für den Fehlerfall vereinbar, was ebenfalls inzwischen weggefallen ist.
    • defaults.ajax ermöglicht Vorgabewerte.
    • Im Übrigen entsprechen die möglichen Optionen denen, die auch bei jQuery.ajax() als settings dokumentiert sind.
  • tokenType – Zeichenkette: "csrf", "login", "watch", "patrol", "rollback", "edit", …

Generell sind bei mw.Api noch einige statische Informationen erhältlich:

.Api.errors[]
Liste der schweren Fehler, die auftreten können
.Api.warnings[]
Liste der Warnmeldungen, die auftreten können

Elementares Beispiel Bearbeiten

Das folgende kleine Beispiel fragt nach Informationen über das aktuelle Wiki:

var a = new mw.Api();
a.get( { meta: 'siteinfo' } )
 .done( function ( answer ) { console.log( answer ); } );
  • Zunächst wird als Variable a eine Instanz generiert.
  • Auf diese Instanz wird eine get-Abfrage angewendet.
  • Die Vorgabe für die Aktion ist 'query' (Abfrage). Es muss nur noch näher spezifiziert werden, was für eine Abfrage erfolgen soll; hier das Objekt:
    { meta: 'siteinfo' }
  • Auf den Abfrage-Aufruf .get() wird die Funktion .done() angewendet. Dies ist eine von mehreren Möglichkeiten, die Callback-Funktion zu vereinbaren.
    • Als Argument von .done() wurde eine anonyme Funktion gewählt. Sie protokolliert das Resultat auf einer Konsole. Genauso könnte hier der Name einer separat definierten Funktion angegeben werden.

Dies entspricht der Abfrage: de.wikipedia.org/w/api.php?action=query&meta=siteinfo

  • Die Antwort ist analog strukturiert.

mw.user Bearbeiten

In der Komponente mw.user des mw-Objekts gibt es eine Funktion, mittels der sich schnell und einfach der für die Ausführung von Aktionen erforderliche Token gewinnen lässt:

  • mw.user.tokens.get("editToken")
    • Für Seitenbearbeitung und Neuanlage von Seiten.
  • mw.user.tokens.get("watchToken")
    • Um Seiten zu beobachten oder nicht mehr zu beobachten.

Je nachdem, mit welchen Rechten Benutzer ausgestattet sind und wie das Projekt konfiguriert ist, sind weitere Arten möglich.

  • Die Komponente mw.user steht möglicherweise nicht von Beginn an zur Verfügung. Es empfiehlt sich, die eigentlichen Funktionen erst auszuführen, nachdem alle Module geladen sind. Weil mediawiki.api ohnehin geladen werden muss, kann gleichzeitig auch mediawiki.user abgefordert werden.

Zusatzmodule für mw.Api Bearbeiten

Wenn die Aufgaben über Abfragen hinausgehen, sind unter mw:ResourceLoader/Default modules #mediawiki.api weitere Unterstützungsmodule dargestellt. Sie mussten bis Juni 2018 beim Laden der Ressourcen in die Liste aufgenommen werden. Mittlerweile wurden sie jedoch in das generelle JS-API-Modul integriert, und separate Modul-Anforderungen müssten eliminiert werden.

Die nachstehenden Funktionen können nach Laden des Moduls benutzt werden.

  • Sie sind auf ein mit a=new mw.Api(); generiertes a anzuwenden.
  • Sie hatten gemeinsame Parameter:
    • ok – Callback-Funktion im Erfolgsfall (optional; meist empfehlenswert). Sie erhält ggf. die gewünschten Daten durch Aufruf als ok(arg) übermittelt.
    • err – Callback-Funktion im Fehlerfall (optional)
  • Diese Funktionsparameter ok und err sind durch eine Neuerung überholt worden. Sofortiger Rückgabewert aller dieser Aufrufe ist ein Objekt vom Typ jQuery.Promise – auf dieses Objekt r kann man die jQuery-Callback-Funktionen anwenden, also mit r.done(fine) beliebig viele eigene ok-Funktionen registrieren, die aufgerufen werden, sobald das Ergebnis vom Server eintrifft.
.getCategories(title, ok, err, async)
Finde alle Kategorien, zu denen eine bestimmte Seite title gehört.
  • Hinweis: Für die aktuell betrachtete Seite ist dies auch über wgCategories feststellbar.
Mit async=false ließ sich eine synchrone Abfrage ausführen; diese konnte jegliche Browser-Aktion blockieren, bis eine Antwort eintrifft.
An ok(arg) wurde ein Array mit allen Titeln übergeben, sonst false.
Modul: mediawiki.api.category
.getCategoriesByPrefix(prefix, ok, err)
Finde alle Kategorien, deren Titel mit prefix beginnt.
An ok(arg) wurde ein Array mit allen Titeln übergeben.
Modul: mediawiki.api.category
.getMessages(messages)
Frage einen Satz von Systemnachrichten in der Benutzersprache ab.
  • Parameter-Format wie ammessages – Zeichenkette mit durch Pipes getrennter Liste von Bezeichnern, oder "*" für ziemlich viele, oder Array mit Zeichenketten.
Modul: mediawiki.api.messages
.getUserInfo()
Benutzergruppen und Rechte des momentanen Benutzers abfragen
Modul: mediawiki.api.user
.isBlacklisted(title, ok, err)
Stelle fest, ob der Seitenname title auf einer schwarzen Liste steht.
An ok(arg) wurde true oder false übergeben.
Modul: mediawiki.api.titleblacklist
.isCategory(title, ok, err)
Stelle fest, ob eine Kategorie title existiert.
An ok(arg) wurde true oder false übergeben.
Modul: mediawiki.api.category
.loadMessages(messages)
Lädt einen Satz von Nachrichten in der aktuellen Benutzersprache und fügt sie mw.messages hinzu.
Modul: mediawiki.api.messages
.loadMessagesIfMissing(messages)
Lädt einen Satz von bislang fehlender Nachrichten in der aktuellen Benutzersprache und fügt sie mw.messages hinzu.
Modul: mediawiki.api.messages
.newSection(title, header, message, ok, err)
Hänge einen neuen Abschnitt an eine Seite an; kümmere dich selbst um einen geeigneten Token.
Der Seiten-Name wird über title gesucht, header ist die Abschnittsüberschrift und message der Wikitext.
Modul: mediawiki.api.edit
.parse(wikitext, ok, err)
Transformiere den wikitext analog mw:API:Parsing wikitext #parse.
An ok(arg) wurde ein HTML-Text übergeben.
Modul: mediawiki.api.parse
.postWithEditToken(params, ok, err)
Führe eine Seitenbearbeitung aus; kümmere dich selbst um einen geeigneten Token.
params ist ein JS-Objekt mit Einzelheiten (identisch mit denen, die bei einem Aufruf von .post() anzugeben wären; also Seiten-Identifikation und neuer Text, auch Bearbeitungskommentar und „Kleine Änderung“).
Modul: mediawiki.api.edit
.saveOption(single, value)
Wert einer Benutzereinstellung setzen
  • single Schlüsselwort für die Einstellung
  • value Zeichenkette oder null
Modul: mediawiki.api.options
.saveOptions(options)
Werte von Benutzereinstellungen setzen
  • options object als { name1: value1, name2: value2, ... }
Modul: mediawiki.api.options
.unwatch(page, ok, err)
Entferne page von der persönlichen Beobachtungsliste.
Modul: mediawiki.api.watch
.watch(page, ok, err)
Setze page auf die persönliche Beobachtungsliste.
Modul: mediawiki.api.watch

Quellcodes:

Der logischen Vollständigkeit halber ist mediawiki.util hier explizit mit angegeben. Tatsächlich würde bei der Auflösung der Anforderung durch den ResourceLoader die jeweils erforderliche Basis-Software auch selbsttätig nachgefordert werden; mediawiki.api stellt mediawiki.util sicher. Eine höhere Funktionalität wie mediawiki.api.edit sorgt automatisch für das Laden von mediawiki.api – es schadet aber auch nicht, dies von vornherein anzugeben, und könnte möglicherweise Abläufe beschleunigen.

Auswertung des Ergebnisses Bearbeiten

In vielen Fällen will man dem Ergebnis Daten entnehmen; namentlich bei einer query. Auch bei Aktivitäten liefert die Callback-Funktion eine Erfolgsmeldung.

Egal, auf welche Weise (mit oder ohne Nutzung der Funktionen in mw.Api) erhält die Callback-Funktion für eine erfolgreiche Abfrage ein strukturiertes Objekt; vorausgesetzt, dass bei der Anfrage das Resultat als JSON zurückgeliefert werden soll, wie das standardmäßig der Fall ist.

Je nach gestellter Frage ist der erste Parameter data in der Callback-Funktion unterschiedlich strukturiert. Die oberste Ebene ist immer ein Objekt; aber die erwarteten Komponenten sind möglicherweise nicht vorhanden, weil vermutete Seiten usw. überhaupt nicht existieren. Der direkte Zugriff auf Unterkomponenten würde dann einen Laufzeitfehler auslösen. Besser ist es, die Existenz der vermuteten Komponente jeweils abzuprüfen.

Einen ersten Überblick über die zu erwartende Struktur gibt eine interaktive Abfrage, deren XML-Ergebnis auf einer HTML-Seite dargestellt wird. Wie bei den im Manual als Beispiele angegebenen URL kann man sich an die sinnvolle Fragestellung herantasten; die Struktur des Ergebnisses wird dann identisch sein. Das Element <query> in XML ist gleichzeitig die Komponente data.query in JSON. Eine weitere Hilfe ist es, das eintreffende Objekt in einem JS-Debugger strukturiert darzustellen und dementsprechend die Programmstruktur zu entwickeln.

In vielen Fällen ist es sinnvoll, bei Definition einer Abfrage nach Seiten indexpageids:true aufzunehmen. Das Ergebnis enthält dann auch ein Array mit den Seiten-Nummern, mit dessen Hilfe sich ggf. einfacher durch die einschlägige Komponente des Ergebnisses iterieren lässt.

Wenn auf die Abfrage mehr Einzelantworten lieferbar sind als mit einer Frage allein zulässigerweise beantwortet werden können, gibt es in der Antwort ein Element data["query-continue"] – diese Komponente enthält einen Hinweis, ab welcher Seiten-Nummer usw. eine Nachfolge-Abfrage beginnen soll.

Wenn man eine unbestimmte Anzahl von Einzelergebnissen erwartet, gibt es die Möglichkeit, den jeweiligen Parameter xxlimit auf "max" zu setzen; dies bewirkt im Regelfall 500. Außerdem wird zurückgemeldet, zu wie vielen Einzeldaten dieser Benutzer bei diesem Typ von Abfrage berechtigt ist. Ist man tatsächlich etwa nur an dem allerjüngsten Einzelergebnis interessiert, sollte das entsprechende xxlimit auf 1 gesetzt werden, um Netzwerk-Verkehr, Server-Belastung und Antwortzeit möglichst gering zu halten.

Ausführliches Beispiel Bearbeiten

var found  =  function ( data ) {
   // Erfolgreich. Ergebnis analysieren.
   var i, page, pageids, pages, revisions,
       id     =  -1,
       query  =  data.query,
       k      =  0;
   if ( query ) {
      pageids  =  query.pageids;
      if ( pageids ) {
         id  =  pageids[ 0 ];
      }
      pages  =  query.pages;
      if ( pages  &&  id > 0 ) {
         page  =  pages[ id ];
         if ( page ) {
            revisions  =  page.revisions;
            if ( revisions ) {
               for ( i = 0;  i < revisions.length;  i++ ) {
                  if ( revisions[ i ].comment.indexOf( "rückgängig gemacht" )  >  0 ) {
                     k++;
                  }
               }   // for i
            }
         }
      }
   }
   window.console.info( "Die Hauptseite wurde " + k + " Mal zurückgesetzt." );
   if ( data[ "query-continue" ] ) {
      window.console.info( "Die Hauptseite wurde mehr als 100 Mal geändert." );
   }
};   // found()


var fault  =  function ( uhff ) {
   // Fehlgeschlagen.
   window.console.warn( "API-Abfrage hat nicht geklappt." );
   window.console.log( uhff );
};   // fault()


var fire  =  function () {
   // Löse eine Abfrage aus: Was sind die letzten 100 Versionen der Hauptseite?
   var p  =  { prop:         "revisions",
               rvlimit:      100,
               rvslots:      "main",
               indexpageids: true,
               titles:       "Wikipedia:Hauptseite"
             },
       q  =  new mw.Api();
   q.get( p ).done( found ).fail( fault );
};   // fire()


mw.loader.using( [ "mediawiki.api",
                   "mediawiki.util" ],
                 fire );
  • Zunächst stehen die Deklarationen der Einzelfunktionen.
  • Abschließend, nachdem alle Einzelfunktionen bekannt sind, werden mit mw.loader.using die Module abgefordert. Sobald sie bereit sind, wird die Funktion fire() aufgerufen, die ja zuvor definiert wurde.
  • Diese Abfrage wird gestartet.
  • In der Funktion found() wird das Ergebnis analysiert. Dabei wird konservativ vorgegangen und das Fehlen jeder Komponente in Betracht gezogen.
  • Das Argument data enthält die Komponente query, die der gleichnamigen Komponente der XML-Antwort entspricht.
  • Weil die Anfrage indexpageids gefordert hatte, ist unter query.pageids ein Array verfügbar, das die curid aller gefundener Seiten aufführt. Es kommt vor, dass auch negative Seitennummern auftauchen, weil Seiten unzugänglich sind.
  • Die Komponente query.pages ist zurzeit kein Array, sondern ein Objekt. Damit sind die einzelnen Seiten nicht unmittelbar zugreifbar. Es kann iteriert werden, oder das Array query.pageids für den Zugriff genutzt werden.
  • Im konkreten Fall enthält query.pageids genau ein Element, das die momentane Seitennummer zum Namen Wikipedia:Hauptseite wiedergibt.
  • Nachdem damit auf die (hier einzige) Seite page zugegriffen wurde, kann mit page.revisions ein Array ausgewertet werden.
  • rvslots:"main" ist mittlerweile vorgeschrieben, obwohl es praktisch keine Anwendung gibt, bei der in einer Seite ein anderer „Slot“ als main verfügbar wäre. Fehlt die Angabe, wird darauf zurückgefallen. Im vorliegenden Beispiel wird jedoch auf die gesamte Seite zugegriffen; damit ist eine Auswertung der Slot-Eigenschaften nicht erforderlich.
  • Falls eine Abfrage fortgesetzt werden soll, ist das durch Auswertung von data[ "query-continue" ].revisions.rvcontinue möglich; damit kann eine neue Abfrage konstruiert werden.
  • Wenn die Abfrage völlig fehlschlägt, wird die Funktion fault() aufgerufen. Sie protokolliert das Objekt mit Details. Das Fehlen von zutreffenden Daten ist in diesem Sinne kein Fehlschlag, jedoch ungültige Parametersyntax oder unerreichbarer Server.

Code-Beispiel zu query-continue Bearbeiten

var api = new mw.Api(),
    carryon = function( queryContinue ) {
                 var params = { action: "query",
                                generator: "watchlistraw",
                                prop: "info",
                                gwrlimit: "max",
                                gwrnamespace: "0"
                              },
                     page;
      if ( queryContinue ) {
         params.gwrcontinue = queryContinue;
      }
      api.get( params, {
        Ok: function( args ) {
               for ( page in args.query.pages ) {
                  if ( args.query.pages[ page ].missing === "" ) {
                     Api.unwatch( args.query.pages[ page ].title );
                  }
               }   // for
               if ( args["query-continue"] ) {
                  carryon( args["query-continue"].watchlistraw.gwrcontinue );
               } else {
                  alert( "all done" );
               }
              }   // Ok()
             } );
            };   // carryon()

Führt eine Ent-Beobachtung im ANR aus. Es wird das maximale Limit beobachteter Artikel abgerufen, diese werden auf unbeobachtet gesetzt; sollte es mehr als das Limit geben, dann wird erneut bis zum maximalen Limit abgerufen usw.

Andere Wiki-Projekte Bearbeiten

Mit einigen Einschränkungen ist es möglich, per API mit dem Inhalt eines anderen WMF-Projektes zu kommunizieren.

Aus Sicherheitsgründen sind derartige Aktionen außerhalb des eigenen Projektes an strikte Regeln gebunden. Die Erlaubnis zum Cross-Domain-Scripting öffnet eine fundamentale Sicherheitslücke im Konzept der Same-Origin-Policy. Ein von einer beliebigen fremden Website untergeschobener JavaScript-Code könnte fatale Folgen haben. Projektseiten der WMF kommunizieren jedoch, welchen anderen Domains sie vertrauen und ermöglichen in diesem Rahmen Cross-Origin Resource Sharing (CORS).

Insbesondere ist zur Einhaltung der Sicherheitsregeln auch streng auf das identische Protokoll http bzw. https zu achten.

Am einfachsten ist es, ein fremdes Projekt lediglich abzufragen.

Beispiel für eine Abfrage in einer anderen Wikipedia Bearbeiten

var fire  =  function ( about, abroad ) {
   // Löse eine Frage nach der jüngsten Versionsgeschichte einer Interlanguage-Seite aus.
   // @param {string} about   -- Name/n der gewünschten Seite/n
   // @param {string} abroad  -- Zwei/Drei-Buchstaben-Code der anderen Wikipedia, etwa "en"
   var h  =  document.location.hostname,
       o  =  { url:    "//" + abroad + h.substr( h.indexOf( "." ) )
                            + mw.util.wikiScript( "api" )
             },
       p  =  { prop:   "revisions",
               titles: about
             },
       q  =  new mw.Api();
   p.origin  =  document.location.protocol + "//" + h;
   q.get( p, o ).done( found ).fail( fault );
};   // fire()
  • Die Option o setzt die URL der anderen Wikipedia zusammen.
    • Genau genommen ist es ein Interlanguage, also die gleiche (beliebige) Projekt-Art in einer anderen Sprache.
    • Mit o.url ist anzugeben, dass eine andere URL als die in .Api standardmäßig für das eigene Wiki vorgegebene benutzt werden soll.
    • Die protokoll-relative URL ist hier möglich und sinnvoll; es wird das Protokoll der umgebenden Seite geerbt.
    • mw.util.wikiScript("api") holt den gültigen Pfad-Namen für API-Abfragen.
    • Genauso hätte dies in den new mw.Api(defaults) bei Bildung der Instanz angegeben werden können, wenn q mehrfach zu diesem Zweck benutzt werden soll.
  • Die aktuelle Frage wird wie üblich in p formuliert.
    • Hinzu kommt aber eine Komponente p.origin zur Angabe des Absenders der Anfrage.
    • Diese Objekt-Komponente wird beim Server daraufhin geprüft, ob sie exakt mit der umgebenden HTTP-Kommunikation übereinstimmt, und ob sie den Erwartungen entspricht.
    • Dabei muss das aktuelle Protokoll festgestellt werden; wgServer ist protokoll-relativ und eignet sich nicht.
  • Danach kann die normale Abfrage erfolgen; das Ergebnis wird an found() übermittelt, bei Misserfolg fault() aufgerufen.

mediawiki.ForeignApi Bearbeiten

Das zuvor anzufordernde Modul mediawiki.ForeignApi stellt Hilfsfunktionen bereit, die den Vorgang unterstützen.

Insbesondere wäre new mw.Api(defaults) durch new mw.ForeignApi(URL,defaults) zu ersetzen. Anschließend stehen alle Hilfsfunktionen bereit, die oben für das eigene Wiki erläutert sind.

var fire  =  function ( about, abroad ) {
   // Löse eine Frage nach der jüngsten Versionsgeschichte einer Interlanguage-Seite aus.
   // @param {string} about   -- Name/n der gewünschten Seite/n
   // @param {string} abroad  -- Zwei/Drei-Buchstaben-Code der anderen Wikipedia, etwa "en"
   var host = document.location.hostname,
       url  = document.location.protocol + "//" 
              + abroad + host.substr( host.indexOf( "." ) )
              + mw.util.wikiScript( "api" ),
       prop = { prop:   "revisions",
                titles: about
              },
       qobj = new mw.ForeignApi( url );
   qobj.get( prop ).done( found ).fail( fault );
};   // fire()

Um 2017 wurde eine auf REST basierende Schnittstelle produktiv eingeführt. Ob das klassische Format dann langfristig weiterhin voll unterstützt werden würde, steht dahin. Bei Verwendung der Funktionen im mw-Objekt wäre aber anzunehmen, dass Änderungen im Format der Anforderungen und des Ablaufs sich hier innerhalb der von MediaWiki programmierten Software abspielen und die JS-Objekte für Auftrag und Rückmeldung auf Anwenderseite kompatibel bleiben. Ohnehin würde eine Umschaltung von einem Tag auf den anderen alle WMF-Projekte dauerhaft zusammenbrechen lassen; es wäre also zunächst nur eine zusätzliche Technologie.

Weiterentwicklung Bearbeiten

api2.php Bearbeiten

Es gibt Wünsche, die vorhandene Schnittstelle besser nutzbar zu machen. Dazu gehören Versionsinformationen, auf die sich eine Anforderung verlässt, und lokalisierte Nachrichten, sowie Verbesserungen in den Auswertungsmöglichkeiten des Ergebnisses. Wenn bei der Kontaktaufnahme mitgeteilt wird, auf welche API-Version sich die Programmierung verlässt, ist es möglich, dies völlig kompatibel umzusetzen, indem beim Fehlen einer derartigen Angabe konservativ geantwortet wird.

Weitere Informationen Bearbeiten

  • Wikipedia:Technik/Datenbank/API zum Angebot des Wiki-Servers
  • mw:API:Main page – englischsprachige Dokumentation der Kernfunktionen; Stammseite auf MediaWiki.
    • nicht immer vollständig und aktuell
  • Erweiterungen mit eigenen API-Abfragen unter mw:API extensions.
  • api.php – automatisch generierte Dokumentation, die stets aktuell ist und neben Kernfunktionen auch die gültigen Erweiterungen enthält (englisch).

Anmerkungen Bearbeiten

  1. Zurzeit haben alle Benutzer, also auch ohne namentliche Anmeldung, das Recht writeapi. Allerdings ist zumindest der aktuelle Kontext einer Wiki-Seite erforderlich (Cookies), um Tokens zu generieren. Dieser Sitzungs-Kontext entsteht automatisch durch bloßes Betrachten einer Wiki-Seite. Über das Cookie wird eine Sitzung zugeordnet, die noch nicht veraltet sein darf.