API:実装戦略

This page is a translated version of the page API:Implementation Strategy and the translation is 100% complete.

これは MediaWiki コアの API の機構の実行方法を説明します。 API をコードを書いてクライアントに使用してもらうには API:拡張機能 をご参照ください。

ファイル/モジュール構造

  • api.php はエントリ ポイントであり、ウィキのルート (root) に設置されています。 API:メインページ#エンドポイントも参照。
  • includes/api は API に関連するすべてのファイルを含みますが、それらのうちどれもエントリ ポイントとしては許可されません。
  • すべての API クラスは共通の抽象クラスである ApiBase から派生します。 基底クラスは、パラメーターの構文解析、プロファイリング、とエラー処理のような共通の機能を提供します。
  • ApiMainapi.php によってインスタンス化されるメイン クラスです。 action=XXX パラメーターに基づき実行するモジュールを決定します。 ApiMain は、出力データの配列と関連のヘルパー関数を含む ApiResult クラスのインスタンスの作成もします。 最後に ApiMain は書式整形クラスをインスタンス化、ApiResult から XML/JSON/PHP その他の形式でデータをクライアントに出力します。
  • ApiBase から派生したどのモジュールもインスタンス化する間に ApiMain のインスタンスへの参照を受け取るので、実行の間にモジュールは結果のオブジェクトといった共有リソースを取得することがあります。

クエリ モジュール群

  • ApiQuery は下位モジュールを実行するという点で ApiMain と同じ振る舞いをします。 それぞれの下位モジュールは ApiQueryBase から派生します(トップ レベルのモジュールである ApiQuery 自身は除く)。 インスタンス化する間、下位モジュールは ApiQuery のインスタンスへの参照を受け取ります。
  • 拡張クエリ モジュールはすべて、必ず 3 文字以上の接頭辞を付けます。 コア モジュール接頭辞は 2 文字です。
  • ApiQuery の実行計画:
    1. 必要な下位モジュールを決定するために共有クエリ パラメーター list/prop/meta を取得する。
    2. ApiPageSet オブジェクトを作り titles/pageids/revids パラメータからそれを投入する。 pageset オブジェクトはクエリ モジュールが連携するページまたは版の一覧を含みます。
    3. 必要な場合、別の PageSet を作るために generator モジュールが実行されます。 UNIX でストリームをパイプするのと似ています。 任意のページは取り組む他のすべてのモジュールに対してページの別の一式を生み出す generator への入力です。
  • クエリ継続の必要条件:
    • SQL クエリは完全に順序付けする必要があります。 言い換えるなら、クエリはすべての列を使い、特定の固有のキーを WHERE 節または ORDER BY 節にある定数として提供します。
      • MySQL では、これは排他的論理和であり、クエリの FooBar のどちらも名前空間順ではなくページ名順に並べ (名前空間は定数 0)、FooTalk:Foo はページ名順ではなく名前空間順に並べ (ページ名は定数 "Foo")、FooTalk:Bar は名前空間順とページ名順の両方に従って並べる必要があります。
    • SQL クエリは filesort (クイックソート) してはいけません。
    • setContinueEnumParameter() に与える値は ORDER BY 節の全列を含みます。
    • 継続するには WHERE 節に単一の複合条件を追加します。 クエリに ORDER BY column_0, column_1, column_2 が含まれると、この条件は以下のようになります:
(column_0 > value_0 OR (column_0 = value_0 AND
 (column_1 > value_1 OR (column_1 = value_1 AND
  (column_2 >= value_2)
 ))
))

もちろん、ORDER BY 列が DESC を使用する場合は「>」と「<」を入れ替えます。 値に SQL を導入しないよう注意します。

内部のデータ構造

  • クエリの API は 1 つのたらい回しにされるグローバルな入れ子の array() 構造のとても連続した構造を持ちます。 さまざまなモジュールはデータのピースを多くの異なる配列のポイントに追加し、最後には、それはプリンター (出力モジュール) の 1 つによるクライアントに対してレンダリングされます。 API のために、筆者はこの配列を個別のリーフ ノードを追加するヘルパー関数を持つクラスとしてラップすることを提案します。

エラー/ステータスの報告

これまで開発者達はエラー情報を通常の結果として同じ構造化された出力に含めることを決定しました(オプション #2)。

結果に関して、標準的な HTTP エラー コードを使うまたは適切に整形されたデータを返すかのどちらかを行うことになります:

HTTP コードを使用
void header( string reason_phrase [, bool replace [, int http_response_code]] )

header() はオペレーションの戻り値ステータスを設定するために使用できます。 reason_phrase の可能なすべての値を定義できるので、失敗したログインに関しては code=403phrase="BadPassword" を返す一方で、成功した場合ヘッダーを変えることなく単にレスポンスを返します。

長所: これは標準です。 クライアントは常に HTTP エラーを処理する必要があるため、結果に対する HTTP コードを使用することで実行する個別のクライアント エラー処理を除去します。 クライアントは複数の書式のデータをリクエストするため、無効な書式パラメーターは、別の HTTP エラー コードになることから、まだ適切に処理されます。

短所: ...

適切なレスポンス内部のエラー情報を含める

このメソッドは適切に整形されたレスポンス オブジェクトを常に返しますが、エラー ステータス/説明はそのオブジェクト内のみの値になります。 これはクエリ API がステータスコードを返す方法と似ています。

長所: HTTP エラー コードはデータ (論理エラー) ではなくネットワークの問題のためのみに使用されます。 既存の HTTP エラー コードに頼りません。

短所: データ形式パラメーターが適切に設定されていない場合、出力データの形式は何になりますか? エラーを知るためにオブジェクトを解析しなければなりません (perf?)。 エラー チェックのコードは接続とデータ解析レベルの両方に存在しなければなりません。

ボイラープレートコード

単純な API モジュール
<?php

class Api<モジュール名> extends ApiBase {
	public function __construct( $main, $action ) {
		parent::__construct( $main, $action );
	}

	public function execute() {
		
	}

	public function getAllowedParams() {
		return array(
			'<パラメーター名>' => array(
				ApiBase::PARAM_TYPE => array( 'foo', 'bar', 'baz' ),
			),
		);
	}

	public function getParamDescription() {
		return array(
			'<パラメーター名>' => '<パラメーターの説明>',
		);
	}

	public function getDescription() {
		return '<ここにモジュールの説明を記載>';
	}

	public function getExamples() {
		return array(
			'api.php?action=<モジュール名>&<パラメーター名>=foo'
		);
	}

	public function getHelpUrls() {
		return '';
	}
}