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.php
ist der Eingangspunkt und befindet sich im Wiki-Root. Siehe API:Hauptseite#Der Endpunkt.includes/api
wird 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
ApiBase
ab. Die Basisklasse bietet übliche Funktionen wie das Parsen von Parametern, Profilierung und Umgang mit Fehlern. ApiMain
ist die vonapi.php
instantiierte Hauptklasse. Sie bestimmt, welches Modul basierend auf dem Parameteraction=XXX
ausgeführt wird.ApiMain
erstellt auch eine Instanz der KlasseApiResult
, die das Ausgabe-Datenarray und verwandte Hilfsfunktionen enthält. Schließlich instantiiertApiMain
die Formatierungsklasse, die die Daten ausApiResult
in XML/JSON/PHP oder einem anderen Format an den Klienten ausgibt.- Jedes von
ApiBase
abgeleitete Modul wird einen Verweis auf eine Instanz vonApiMain
während der Instantiierung erhalten, sodass das Modul während der Ausführung gemeinsame Quellen wie das Ergebnisobjekt nutzen kann.
Abfragemodule
ApiQuery
verhält sich ähnlich wieApiMain
, in dem es seine Submodule ausführt. Jedes Submodul leitet sich vonApiQueryBase
ab (außerApiQuery
selbst, 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.
ApiQuery
Ausfü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
PageSet
zu 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_2
hat, 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 '';
}
}
|