Jump to content

API:Implementation Strategy/cs: Difference between revisions

From mediawiki.org
Content deleted Content added
Created page with "Ujistěte se, že se v hodnotách vyhnete vkládání SQL."
Created page with "$1 je implementace vstupního bodu (vyloučeno v $2)."
 
(40 intermediate revisions by 2 users not shown)
Line 6: Line 6:
<span id="File/Module_Structure"></span>
<span id="File/Module_Structure"></span>
== Struktura souboru/modulu ==
== Struktura souboru/modulu ==
* <code>api.php</code> je vstupní bod umístěný v kořenovém adresáři wiki. Viz [[Special:MyLanguage/API:Main page#The endpoint|API:Hlavní stránka#Koncový bod]].
* <code>api.php</code> je vstupní bod umístěný v kořenovém adresáři wiki. Viz [[Special:MyLanguage/API:Main page#Endpoint|API:Hlavní stránka#Koncový bod]].
* <code>ApiEntryPoint</code> je implementace vstupního bodu (vyloučeno v {{gerrit|959047}}).
* <code>includes/api</code> bude obsahovat všechny soubory související s API, ale žádný z nich nebude povolen jako vstupní bod.
* <code>includes/api</code> bude obsahovat všechny soubory související s API, ale žádný z nich nebude povolen jako vstupní bod.
* Všechny třídy API jsou odvozeny od společné abstraktní třídy <code>ApiBase</code>. Základní třída poskytuje běžné funkce, jako je analýza parametrů, profilování a zpracování chyb.
* Všechny třídy API jsou odvozeny od společné abstraktní třídy <code>ApiBase</code>. Základní třída poskytuje běžné funkce, jako je analýza parametrů, profilování a zpracování chyb.
* <code>ApiMain</code> je hlavní třída vytvořená pomocí <code>api.php</code>. Určuje, který modul se má spustit, na základě parametru <code>action=''XXX''</code>. <code>ApiMain</code> také vytvoří instanci třídy <code>ApiResult</code>, která obsahuje pole výstupních dat a související pomocné funkce. Nakonec <code>ApiMain</code> vytvoří instanci formátovací třídy, která klientovi vyvede data z <code>ApiResult</code> ve formátu XML/JSON/PHP nebo v jiném formátu.
* <code>ApiMain</code> je hlavní třída vytvořená pomocí <code>ApiEntryPoint</code>. Určuje, který modul se má spustit, na základě parametru <code>action=''XXX''</code>. <code>ApiMain</code> také vytvoří instanci třídy <code>ApiResult</code>, která obsahuje pole výstupních dat a související pomocné funkce. Nakonec <code>ApiMain</code> vytvoří instanci formátovací třídy, která klientovi vyvede data z <code>ApiResult</code> ve formátu XML/JSON/PHP nebo v jiném formátu.
* Jakýkoli modul odvozený z <code>ApiBase</code> obdrží během vytváření instance odkaz na instanci <code>ApiMain</code>, takže během provádění může modul získat sdílené prostředky, jako je výsledný objekt.
* Jakýkoli modul odvozený z <code>ApiBase</code> obdrží během vytváření instance odkaz na instanci <code>ApiMain</code>, takže během provádění může modul získat sdílené prostředky, jako je výsledný objekt.


Line 19: Line 20:
*# Získejte sdílené parametry dotazu <code>list/prop/meta</code> k určení potřebných submodulů.
*# Získejte sdílené parametry dotazu <code>list/prop/meta</code> k určení potřebných submodulů.
*# Vytvořte objekt <code>ApiPageSet</code> a naplňte jej z parametrů <code>titles/pageids/revids</code>. Objekt <code>pageset</code> obsahuje seznam stránek nebo revizí, se kterými budou moduly dotazů pracovat.
*# Vytvořte objekt <code>ApiPageSet</code> a naplňte jej z parametrů <code>titles/pageids/revids</code>. Objekt <code>pageset</code> obsahuje seznam stránek nebo revizí, se kterými budou moduly dotazů pracovat.
*# Na požádání se spustí modul generátoru k vytvoření dalšího <code>PageSet</code>. Podobné jako piping streams v UNIXu. Dané stránky jsou vstupem do generátoru, který vytváří další sadu stránek pro všechny ostatní moduly, na kterých mohou pracovat.
*# Na požádání se spustí modul generátoru k vytvoření dalšího <code>ApiPageSet</code>. Podobné jako piping streams v UNIXu. Dané stránky jsou vstupem do generátoru, který vytváří další sadu stránek pro všechny ostatní moduly, na kterých mohou pracovat.
* Požadavky na pokračování dotazu:
* Požadavky na pokračování dotazu:
** SQL dotaz musí být zcela uspořádaný. Jinými slovy, dotaz musí používat všechny sloupce nějakého jedinečného klíče buď jako konstanty v klauzuli <code>WHERE</code> nebo v klauzuli <code>ORDER BY</code>.
** SQL dotaz musí být zcela uspořádaný. Jinými slovy, dotaz musí používat všechny sloupce nějakého jedinečného klíče buď jako konstanty v klauzuli <code>WHERE</code> nebo v klauzuli <code>ORDER BY</code>.
Line 28: Line 29:


<pre>
<pre>
(column_0 > value_0 OR (column_0 = value_0 AND&#xa; (column_1 > value_1 OR (column_1 = value_1 AND&#xa; (column_2 >= value_2)&#xa; ))&#xa;))
(column_0 > value_0 OR (column_0 = value_0 AND
(column_1 > value_1 OR (column_1 = value_1 AND
(column_2 >= value_2)
))
))
</pre>
</pre>


Line 34: Line 39:
Ujistěte se, že se v hodnotách vyhnete vkládání SQL.
Ujistěte se, že se v hodnotách vyhnete vkládání SQL.


<span id="Internal_data_structures"></span>
<div lang="en" dir="ltr" class="mw-content-ltr">
== Internal data structures ==
== Vnitřní datové struktury ==
* Query API má velmi úspěšnou strukturu jedné globální vnořené struktury <code>array()</code>. Různé moduly by přidávaly kusy dat do mnoha různých bodů tohoto pole, až by je nakonec pro klienta vykreslila jedna z tiskáren (výstupní moduly). Pro rozhraní API doporučujeme zabalit toto pole jako třídu s pomocnými funkcemi pro připojení jednotlivých listových uzlů.
</div>
* <span lang="en" dir="ltr" class="mw-content-ltr">Query API has had very successful structure of one global nested <code>array()</code> structure passed around.</span> <span lang="en" dir="ltr" class="mw-content-ltr">Various modules would add pieces of data to many different points of that array, until, finally, it would get rendered for the client by one of the printers (output modules).</span> <span lang="en" dir="ltr" class="mw-content-ltr">For the API, we suggest wrapping this array as a class with helper functions to append individual leaf nodes.</span>


<span id="Error/status_reporting"></span>
<div lang="en" dir="ltr" class="mw-content-ltr">
== Error/status reporting ==
== Hlášení chyb/stavu ==
</div>


Prozatím jsme se rozhodli zahrnout informace o chybě do stejného strukturovaného výstupu jako normální výsledek (možnost #2).
<div lang="en" dir="ltr" class="mw-content-ltr">
For now we decided to include error information inside the same structured output as normal result (option #2).
</div>


Ve výsledku můžeme buď použít standardní chybové kódy HTTP nebo vždy vrátit správně naformátovaná data:
<div lang="en" dir="ltr" class="mw-content-ltr">
For the result, we may either use the standard HTTP error codes, or always return a properly formatted data:
</div>


; Pomocí HTTP kódu
; <span lang="en" dir="ltr" class="mw-content-ltr">Using HTTP code</span>
<pre>
<pre>
void header( string reason_phrase [, bool replace [, int http_response_code]] )
void header( string reason_phrase [, bool replace [, int http_response_code]] )
</pre>
</pre>
<code>header()</code> lze použít k nastavení návratového stavu operace.
<span lang="en" dir="ltr" class="mw-content-ltr">The <code>header()</code> can be used to set the return status of the operation.</span>
<span lang="en" dir="ltr" class="mw-content-ltr">We can define all possible values of the <code>reason_phrase</code>, so for the failed login we may return <code>code=403</code> and <code>phrase="BadPassword"</code>, whereas for any success we would simply return the response without altering the header.</span>
Můžeme definovat všechny možné hodnoty <code>reason_phrase</code>, takže za neúspěšné přihlášení můžeme vrátit <code>code=403</code> a <code>phrase="BadPassword"</code>, zatímco v případě úspěchu bychom jednoduše vrátili odpověď beze změny hlavičky.


''Výhody'':
<span lang="en" dir="ltr" class="mw-content-ltr">''Pros'':</span>
Je to standard. Klient se vždy musí vypořádat s chybami HTTP, takže použití kódu HTTP pro výsledek by odstranilo jakékoli samostatné zpracování chyb, které by klient musel provést.
<span lang="en" dir="ltr" class="mw-content-ltr">It's a standard.</span> <span lang="en" dir="ltr" class="mw-content-ltr">The client always has to deal with HTTP errors, so using HTTP code for result would remove any separate error handling the client would have to perform.</span>
Vzhledem k tomu, že klient může požadovat data ve více formátech, neplatný parametr formátu by byl stále správně zpracován, protože by to byl jednoduše další kód chyby http.
<span lang="en" dir="ltr" class="mw-content-ltr">Since the client may request data in multiple formats, an invalid format parameter would still be properly handled, as it will simply be another http error code.</span>


''Nevýhody'': ...
<span lang="en" dir="ltr" class="mw-content-ltr">''Cons'':</span> ...


; Zahrnuje informace o chybě do správné odpovědi
; <span lang="en" dir="ltr" class="mw-content-ltr">Include error information inside a proper response</span>
Tato metoda by vždy vrátila správně formátovaný objekt odpovědi, ale chybový stav/popis budou jediné hodnoty uvnitř tohoto objektu.
<span lang="en" dir="ltr" class="mw-content-ltr">This method would always return a properly formatted response object, but the error status/description will be the only values inside that object.</span>
Je to podobné způsobu, jakým aktuální Query API vrací stavové kódy.
<span lang="en" dir="ltr" class="mw-content-ltr">This is similar to the way current Query API returns status codes.</span>


''Výhody'':
<span lang="en" dir="ltr" class="mw-content-ltr">''Pros'':</span>
Chybové kódy HTTP se používají pouze pro problémy se sítí, nikoli pro data (logické chyby). Nejsme vázáni na stávající kódy chyb HTTP.
<span lang="en" dir="ltr" class="mw-content-ltr">HTTP error codes are used only for the networking issues, not for the data (logical errors).</span> <span lang="en" dir="ltr" class="mw-content-ltr">We do not tied to the existing HTTP error codes.</span>


''Nevýhody'':
<span lang="en" dir="ltr" class="mw-content-ltr">''Cons'':</span>
Pokud parametr formátu dat není správně zadán, jaký je formát výstupních dat?
<span lang="en" dir="ltr" class="mw-content-ltr">If the data format parameter is not properly specified, what is the format of the output data?</span>
Aplikace musí objekt analyzovat, aby věděla o chybě (výkon?).
<span lang="en" dir="ltr" class="mw-content-ltr">Application has to parse the object to know of an error (perf?).</span>
Kód kontroly chyb bude muset být na úrovni připojení i analýzy dat.
<span lang="en" dir="ltr" class="mw-content-ltr">Error checking code will have to be on both the connection and data parsing levels.</span>


<span id="Boilerplate_code"></span>
<div lang="en" dir="ltr" class="mw-content-ltr">
== Boilerplate code ==
== Kód Boilerplate ==
</div>
{{merge|API:Extensions#ApiSampleApiExtension.php}}
{{merge|API:Extensions#ApiSampleApiExtension.php}}
{{collapse top|1=<span lang="en" dir="ltr" class="mw-content-ltr">Simple API module</span>}}
{{collapse top|1=Jednoduchý modul API}}
<syntaxhighlight lang=php>
<syntaxhighlight lang=php>
<?php
<?php


class Api<module name> extends ApiBase {
class Api<název modulu> extends ApiBase {
public function __construct( $main, $action ) {
public function __construct( $main, $action ) {
parent::__construct( $main, $action );
parent::__construct( $main, $action );
Line 95: Line 93:
public function getAllowedParams() {
public function getAllowedParams() {
return array(
return array(
'<parameter name>' => array(
'<název parametru>' => array(
ApiBase::PARAM_TYPE => array( 'foo', 'bar', 'baz' ),
ApiBase::PARAM_TYPE => array( 'foo', 'bar', 'baz' ),
),
),
Line 103: Line 101:
public function getParamDescription() {
public function getParamDescription() {
return array(
return array(
'<parameter name>' => '<parameter description>',
'<název parametru>' => '<popis parametru>',
);
);
}
}


public function getDescription() {
public function getDescription() {
return '<Module description here>';
return '<Popis modulu zde>';
}
}


public function getExamples() {
public function getExamples() {
return array(
return array(
'api.php?action=<module name>&<parameter name>=foo'
'api.php?action=<název modulu>&<název parametru>=foo'
);
);
}
}

Latest revision as of 17:33, 20 July 2026

Vysvětluje implementaci MediaWiki API v jádru. Pokud chcete ve svém kódu poskytnout rozhraní API pro klienty k použití, přečtěte si API:Rozšíření .

Struktura souboru/modulu

  • api.php je vstupní bod umístěný v kořenovém adresáři wiki. Viz API:Hlavní stránka#Koncový bod.
  • ApiEntryPoint je implementace vstupního bodu (vyloučeno v Gerrit change 959047).
  • includes/api bude obsahovat všechny soubory související s API, ale žádný z nich nebude povolen jako vstupní bod.
  • Všechny třídy API jsou odvozeny od společné abstraktní třídy ApiBase. Základní třída poskytuje běžné funkce, jako je analýza parametrů, profilování a zpracování chyb.
  • ApiMain je hlavní třída vytvořená pomocí ApiEntryPoint. Určuje, který modul se má spustit, na základě parametru action=XXX. ApiMain také vytvoří instanci třídy ApiResult, která obsahuje pole výstupních dat a související pomocné funkce. Nakonec ApiMain vytvoří instanci formátovací třídy, která klientovi vyvede data z ApiResult ve formátu XML/JSON/PHP nebo v jiném formátu.
  • Jakýkoli modul odvozený z ApiBase obdrží během vytváření instance odkaz na instanci ApiMain, takže během provádění může modul získat sdílené prostředky, jako je výsledný objekt.

Moduly dotazů

  • ApiQuery se chová podobně jako ApiMain v tom, že spouští submoduly. Každý submodul je odvozen od ApiQueryBase (kromě samotného ApiQuery, což je modul nejvyšší úrovně). Během vytváření instance obdrží submoduly odkaz na instanci ApiQuery.
  • Všechny moduly dotazů rozšíření by měly používat 3 nebo více písmenných předpon. Základní moduly používají 2 písmenné předpony.
  • Realizační plán ApiQuery:
    1. Získejte sdílené parametry dotazu list/prop/meta k určení potřebných submodulů.
    2. Vytvořte objekt ApiPageSet a naplňte jej z parametrů titles/pageids/revids. Objekt pageset obsahuje seznam stránek nebo revizí, se kterými budou moduly dotazů pracovat.
    3. Na požádání se spustí modul generátoru k vytvoření dalšího ApiPageSet. Podobné jako piping streams v UNIXu. Dané stránky jsou vstupem do generátoru, který vytváří další sadu stránek pro všechny ostatní moduly, na kterých mohou pracovat.
  • Požadavky na pokračování dotazu:
    • SQL dotaz musí být zcela uspořádaný. Jinými slovy, dotaz musí používat všechny sloupce nějakého jedinečného klíče buď jako konstanty v klauzuli WHERE nebo v klauzuli ORDER BY.
      • V MySQL se jedná o exclusive or až do bodu, kdy se dotazování Foo a Bar musí řadit podle názvu, ale nikoli jmenného prostoru (jmenný prostor je konstantní 0), Foo a Talk:Foo se musí řadit podle jmenného prostoru, ale ne podle názvu (název je konstantní "Foo") a Foo a Talk:Bar se musí řadit podle jmenného prostoru i názvu.
    • SQL dotaz nesmí řadit soubory.
    • Hodnota přidělená setContinueEnumParameter() musí zahrnovat všechny sloupce v klauzuli ORDER BY.
    • Při pokračování by měla být do klauzule WHERE přidána jedna složená podmínka. Pokud má dotaz ORDER BY column_0, column_1, column_2, měla by tato podmínka vypadat nějak takto:
(column_0 > value_0 OR (column_0 = value_0 AND
 (column_1 > value_1 OR (column_1 = value_1 AND
  (column_2 >= value_2)
 ))
))

Samozřejmě, vyměňte ">" za "<", pokud vaše sloupce ORDER BY používají DESC. Ujistěte se, že se v hodnotách vyhnete vkládání SQL.

Vnitřní datové struktury

  • Query API má velmi úspěšnou strukturu jedné globální vnořené struktury array(). Různé moduly by přidávaly kusy dat do mnoha různých bodů tohoto pole, až by je nakonec pro klienta vykreslila jedna z tiskáren (výstupní moduly). Pro rozhraní API doporučujeme zabalit toto pole jako třídu s pomocnými funkcemi pro připojení jednotlivých listových uzlů.

Hlášení chyb/stavu

Prozatím jsme se rozhodli zahrnout informace o chybě do stejného strukturovaného výstupu jako normální výsledek (možnost #2).

Ve výsledku můžeme buď použít standardní chybové kódy HTTP nebo vždy vrátit správně naformátovaná data:

Pomocí HTTP kódu
void header( string reason_phrase [, bool replace [, int http_response_code]] )

header() lze použít k nastavení návratového stavu operace. Můžeme definovat všechny možné hodnoty reason_phrase, takže za neúspěšné přihlášení můžeme vrátit code=403 a phrase="BadPassword", zatímco v případě úspěchu bychom jednoduše vrátili odpověď beze změny hlavičky.

Výhody: Je to standard. Klient se vždy musí vypořádat s chybami HTTP, takže použití kódu HTTP pro výsledek by odstranilo jakékoli samostatné zpracování chyb, které by klient musel provést. Vzhledem k tomu, že klient může požadovat data ve více formátech, neplatný parametr formátu by byl stále správně zpracován, protože by to byl jednoduše další kód chyby http.

Nevýhody: ...

Zahrnuje informace o chybě do správné odpovědi

Tato metoda by vždy vrátila správně formátovaný objekt odpovědi, ale chybový stav/popis budou jediné hodnoty uvnitř tohoto objektu. Je to podobné způsobu, jakým aktuální Query API vrací stavové kódy.

Výhody: Chybové kódy HTTP se používají pouze pro problémy se sítí, nikoli pro data (logické chyby). Nejsme vázáni na stávající kódy chyb HTTP.

Nevýhody: Pokud parametr formátu dat není správně zadán, jaký je formát výstupních dat? Aplikace musí objekt analyzovat, aby věděla o chybě (výkon?). Kód kontroly chyb bude muset být na úrovni připojení i analýzy dat.

Kód Boilerplate

Jednoduchý modul API
<?php

class Api<název modulu> extends ApiBase {
	public function __construct( $main, $action ) {
		parent::__construct( $main, $action );
	}

	public function execute() {
		
	}

	public function getAllowedParams() {
		return array(
			'<název parametru>' => array(
				ApiBase::PARAM_TYPE => array( 'foo', 'bar', 'baz' ),
			),
		);
	}

	public function getParamDescription() {
		return array(
			'<název parametru>' => '<popis parametru>',
		);
	}

	public function getDescription() {
		return '<Popis modulu zde>';
	}

	public function getExamples() {
		return array(
			'api.php?action=<název modulu>&<název parametru>=foo'
		);
	}

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