API:Implementationsstrategie
| Diese Seite ist Teil der Dokumentation der MediaWiki action API. |
Dies erklärt die Implementation der MediaWiki-API-Maschine in den Kern. Wenn du in deinem Code eine API für Klienten zum Konsumieren anbieten möchtest, lese API:Erweiterungen.
Datei- / Modulaufbau
api.phpist der Eingangspunkt und befindet sich im Wiki-Root. Siehe API:Hauptseite#Der Endpunkt.ApiEntryPointis the implementation of the entry point (factored out in Gerrit change 959047).includes/apiwird alle Dateien mit Bezug zur API enthalten, jedoch wird keine von ihnen als Eingangspunkt erlaubt sein.- Alle API-Klassen leiten sich von einer gewöhnlichen abstrakten Klasse
ApiBaseab. Die Basisklasse bietet übliche Funktionen wie das Parsen von Parametern, Profilierung und Umgang mit Fehlern. ApiMainist die vonApiEntryPointinstantiierte Hauptklasse. Sie bestimmt, welches Modul basierend auf dem Parameteraction=XXXausgeführt wird.ApiMainerstellt auch eine Instanz der KlasseApiResult, die das Ausgabe-Datenarray und verwandte Hilfsfunktionen enthält. Schließlich instantiiertApiMaindie Formatierungsklasse, die die Daten ausApiResultin XML/JSON/PHP oder einem anderen Format an den Klienten ausgibt.- Jedes von
ApiBaseabgeleitete Modul wird einen Verweis auf eine Instanz vonApiMainwährend der Instantiierung erhalten, sodass das Modul während der Ausführung gemeinsame Quellen wie das Ergebnisobjekt nutzen kann.
Abfragemodule
ApiQueryverhält sich ähnlich wieApiMain, in dem es seine Submodule ausführt. Jedes Submodul leitet sich vonApiQueryBaseab (außerApiQueryselbst, wobei es sich um ein Top-Level-Modul handelt). Während der Instantiierung erhalten Submodule einen Verweis auf die ApiQuery-Instanz.- Alle Abfragemodule von Erweiterungen sollten ein Präfix aus 3 oder mehr Buchstaben nutzen. Die Kernmodule nutzen Präfixe aus 2 Buchstaben.
ApiQueryAusführungsplan:- Erhalte gemeinsame Abfrageparameter
list/prop/meta, um benötigte Submodule zu bestimmen. - Erstelle ein
ApiPageSet-Objekt und befülle es durch dietitles/pageids/revids-Parameter. Daspageset-Objekt enthält die Liste von Seiten oder Versionen, mit denen die Abfragemodule arbeiten werden. - Sofern angefragt wird ein Generatormodul ausgeführt, um ein anderes
ApiPageSetzu erstellen. Ähnlich wie die Pipingstreams in UNIX. Angegebene Seiten sind die Eingabe für den Generator, der eine andere Reihe von Seiten für alle anderen Module erstellt.
- Erhalte gemeinsame Abfrageparameter
- Voraussetzungen für eine Fortsetzung der Abfrage:
- Die SQL-Abfrage muss vollständig korrekt sein. In anderen Worten muss die Abfrage alle Spalten der einzigartigen Schlüssel sowie Konstanten in der
WHERE-Klausel oder denORDER BY-Klauseln nutzen.- In MySQL ist dies ein Exklusiv-oder, an dem Punkt, an dem Foo und Bar abgefragt werden, muss nach Titel, jedoch nicht nach Namensraum sortiert werden (Namensraum ist immer 0), Foo und Talk:Foo müssen nach Namensraum, jedoch nicht nach Titel sortiert werden (Titel ist immer "Foo") und Foo und Talk:Bar müssen nach Namensraum und Titel sortiert werden.
- Die SQL-Abfrage muss nicht Dateisortieren.
- Der an
setContinueEnumParameter()gegebene Wert muss alle Spalten derORDER BY-Klausel enthalten. - Bei Fortführung sollte eine einzelne Verbindungsbedingung zur
WHERE-Klausel hinzugefügt werden. Wenn die AbfrageORDER BY column_0, column_1, column_2hat, sollte die Bedingung in etwa so aussehen:
- Die SQL-Abfrage muss vollständig korrekt sein. In anderen Worten muss die Abfrage alle Spalten der einzigartigen Schlüssel sowie Konstanten in der
(column_0 > value_0 OR (column_0 = value_0 AND (column_1 > value_1 OR (column_1 = value_1 AND (column_2 >= value_2) )) ))
Tausche natürlich "<" durch ">" aus, wenn deine ORDER BY-Spalten DESC nutzen.
Stelle sicher, SQL-Einschübe in den Werten zu vermeiden.
Interne Datenstrukturen
- Die Abfrage-API ist in eine sehr erfolgreiche Struktur einer global verschachtelten
array()-Struktur eingebunden. Unterschiedliche Module würden einzelne Daten zu vielen Unterschiedlichen Punkten des Arrays hinzufügen, bis sie schließlich für den Klienten durch die Ausgabe (Ausgabemodule) gerendert werden würden. Für die API schlagen wir vor, dieses Array als eine Klasse mit Hilfefunktionen einzuschließen, um einzelne Knoten anzuhängen.
Fehler- / Statusmeldungen
Wir haben zunächst entschieden, Fehlerinformationen in der gleichen strukturierten Ausgabe einzubinden, wie ein normales Ergebnis (Option #2).
Für das Ergebnis können wir entweder die Standard-HTTP-Fehlercodes nutzen oder immer angemessen formatierte Daten zurückgeben:
- Nutzung von HTTP-Code
void header( string reason_phrase [, bool replace [, int http_response_code]] )
header() kann genutzt werden, um den Rückgabe-Status der Operation zu setzen.
Wir können alle möglichen Werte von reason_phrase definieren, sodass wir für die fehlgeschlagene Anmeldung code=403 und phrase="BadPassword" ausgeben können, während wir für jeden Erfolg einfach die Antwort ohne Änderung des Headers ausgeben würden.
Pro: Es ist ein Standard. Der Klient muss immer mit HTTP-Fehlern umgehen, sodass die Nutzung von HTTP-Code für Ergebnisse jede andere Fehlerbehandlung, die der Klient ausführen müsste, entfernen würde. Da der Klient Daten in mehreren Formaten anfordern kann, würde ein ungültiger Formatparameter immer noch korrekt behandelt werden, da es einfach ein anderer HTTP-Fehler-Code sein wird.
Kontra: ...
- Fehlerinformationen in einer korrekten Antwort enthalten
Diese Methode wird immer ein korrekt formatiertes Antwortobjekt ausgeben, der Fehlerstatus / die Fehlerbeschreibung wird aber der einzige Wert in dem Objekt sein. Dies ähnelt der Art und Weise, auf die die Abfrage-API Statuscodes zurückgibt.
Pro: HTTP-Fehlercodes werden nur für Netzwerk-Probleme genutzt, nicht für Daten (logische Fehler). Wir sind nicht an die vorhandenen HTTP-Fehlercodes gebunden.
Kontra: Wenn das Datenformat nicht korrekt angegeben ist, was ist das Format der ausgegebenen Daten? Die Anwendung muss das Objekt parsen, um von dem Fehler zu erfahren (perf?). Code, der auf Fehler prüft, muss sich sowohl auf Ebene der Verbindung als auch auf Ebene des Daten-Parsings befinden.
Boilerplate-Code
Es wurde vorgeschlagen, dass diese Seite oder dieser Abschnitt mit API:Extensions#ApiSampleApiExtension.php zusammengeführt wird.(Diskutieren) |
| Einfaches API-Modul |
|---|
<?php
class Api<Modulname> extends ApiBase {
public function __construct( $main, $action ) {
parent::__construct( $main, $action );
}
public function execute() {
}
public function getAllowedParams() {
return array(
'<Parametername>' => array(
ApiBase::PARAM_TYPE => array( 'foo', 'bar', 'baz' ),
),
);
}
public function getParamDescription() {
return array(
'<Parametername>' => '<Parameterbeschreibung>',
);
}
public function getDescription() {
return '<Modulbeschreibung hier>';
}
public function getExamples() {
return array(
'api.php?action=<Modulname>&<Parametername>=foo'
);
}
public function getHelpUrls() {
return '';
}
}
|