API:Implementation Strategy/es: Difference between revisions
Updating to match new version of source page |
Updating to match new version of source page |
||
| (3 intermediate revisions by the same user not shown) | |||
| Line 4: | Line 4: | ||
<span lang="en" dir="ltr" class="mw-content-ltr">If you want to provide an API in your code for clients to consume, read {{ll|API:Extensions}}.</span> |
<span lang="en" dir="ltr" class="mw-content-ltr">If you want to provide an API in your code for clients to consume, read {{ll|API:Extensions}}.</span> |
||
<span id="File/Module_Structure"></span> |
|||
== Estructura de archivo/módulo == |
== Estructura de archivo/módulo == |
||
* <span lang="en" dir="ltr" class="mw-content-ltr"><code>api.php</code> is the entry point, located in the wiki root.</span> <span lang="en" dir="ltr" class="mw-content-ltr">See [[Special:MyLanguage/API:Main page# |
* <span lang="en" dir="ltr" class="mw-content-ltr"><code>api.php</code> is the entry point, located in the wiki root.</span> <span lang="en" dir="ltr" class="mw-content-ltr">See [[Special:MyLanguage/API:Main page#Endpoint|API:Main page#Endpoint]].</span> |
||
* <span lang="en" dir="ltr" class="mw-content-ltr"><code>ApiEntryPoint</code> is the implementation of the entry point (factored out in {{gerrit|959047}}).</span> |
|||
* <span lang="en" dir="ltr" class="mw-content-ltr"><code>includes/api</code> will contain all files related to the API, but none of them will be allowed as entry points.</span> |
* <span lang="en" dir="ltr" class="mw-content-ltr"><code>includes/api</code> will contain all files related to the API, but none of them will be allowed as entry points.</span> |
||
* <span lang="en" dir="ltr" class="mw-content-ltr">All API classes are derived from a common abstract class <code>ApiBase</code>.</span> <span lang="en" dir="ltr" class="mw-content-ltr">The base class provides common functionality such as parameter parsing, profiling, and error handling.</span> |
* <span lang="en" dir="ltr" class="mw-content-ltr">All API classes are derived from a common abstract class <code>ApiBase</code>.</span> <span lang="en" dir="ltr" class="mw-content-ltr">The base class provides common functionality such as parameter parsing, profiling, and error handling.</span> |
||
* <span lang="en" dir="ltr" class="mw-content-ltr"><code>ApiMain</code> is the main class instantiated by <code> |
* <span lang="en" dir="ltr" class="mw-content-ltr"><code>ApiMain</code> is the main class instantiated by <code>ApiEntryPoint</code>.</span> <span lang="en" dir="ltr" class="mw-content-ltr">It determines which module to execute based on the <code>action=''XXX''</code> parameter.</span> <span lang="en" dir="ltr" class="mw-content-ltr"><code>ApiMain</code> also creates an instance of the <code>ApiResult</code> class, which contains the output data array and related helper functions.</span> <span lang="en" dir="ltr" class="mw-content-ltr">Lastly, <code>ApiMain</code> instantiates the formatting class that will output the data from <code>ApiResult</code> in XML/JSON/PHP or other format to the client.</span> |
||
* <span lang="en" dir="ltr" class="mw-content-ltr">Any module derived from <code>ApiBase</code> will receive a reference to an instance of the <code>ApiMain</code> during instantiation, so that during execution the module may get shared resources such as the result object.</span> |
* <span lang="en" dir="ltr" class="mw-content-ltr">Any module derived from <code>ApiBase</code> will receive a reference to an instance of the <code>ApiMain</code> during instantiation, so that during execution the module may get shared resources such as the result object.</span> |
||
<span id="Query_modules"></span> |
|||
=== Módulos de consulta === |
=== Módulos de consulta === |
||
* <span lang="en" dir="ltr" class="mw-content-ltr"><code>ApiQuery</code> behaves similar to <code>ApiMain</code> in that it executes submodules.</span> <span lang="en" dir="ltr" class="mw-content-ltr">Each submodule derives from <code>ApiQueryBase</code> (except <code>ApiQuery</code> itself, which is a top-level module).</span> <span lang="en" dir="ltr" class="mw-content-ltr">During instantiation, submodules receive a reference to the ApiQuery instance.</span> |
* <span lang="en" dir="ltr" class="mw-content-ltr"><code>ApiQuery</code> behaves similar to <code>ApiMain</code> in that it executes submodules.</span> <span lang="en" dir="ltr" class="mw-content-ltr">Each submodule derives from <code>ApiQueryBase</code> (except <code>ApiQuery</code> itself, which is a top-level module).</span> <span lang="en" dir="ltr" class="mw-content-ltr">During instantiation, submodules receive a reference to the ApiQuery instance.</span> |
||
| Line 17: | Line 20: | ||
*# <span lang="en" dir="ltr" class="mw-content-ltr">Get shared query parameters <code>list/prop/meta</code> to determine needed submodules.</span> |
*# <span lang="en" dir="ltr" class="mw-content-ltr">Get shared query parameters <code>list/prop/meta</code> to determine needed submodules.</span> |
||
*# <span lang="en" dir="ltr" class="mw-content-ltr">Create an <code>ApiPageSet</code> object and populate it from the <code>titles/pageids/revids</code> parameters.</span> <span lang="en" dir="ltr" class="mw-content-ltr">The <code>pageset</code> object contains the list of pages or revisions that query modules will work with.</span> |
*# <span lang="en" dir="ltr" class="mw-content-ltr">Create an <code>ApiPageSet</code> object and populate it from the <code>titles/pageids/revids</code> parameters.</span> <span lang="en" dir="ltr" class="mw-content-ltr">The <code>pageset</code> object contains the list of pages or revisions that query modules will work with.</span> |
||
*# <span lang="en" dir="ltr" class="mw-content-ltr">If requested, a generator module is executed to create another <code> |
*# <span lang="en" dir="ltr" class="mw-content-ltr">If requested, a generator module is executed to create another <code>ApiPageSet</code>.</span> <span lang="en" dir="ltr" class="mw-content-ltr">Similar to the piping streams in UNIX.</span> <span lang="en" dir="ltr" class="mw-content-ltr">Given pages are the input to generator that produces another set of pages for all other modules to work on.</span> |
||
* <span lang="en" dir="ltr" class="mw-content-ltr">Requirements for query continuation:</span> |
* <span lang="en" dir="ltr" class="mw-content-ltr">Requirements for query continuation:</span> |
||
** <span lang="en" dir="ltr" class="mw-content-ltr">The SQL query must be totally ordered.</span> <span lang="en" dir="ltr" class="mw-content-ltr">In other words, the query must be using all columns of some unique key either as constants in the <code>WHERE</code> clause or in the <code>ORDER BY</code> clauses.</span> |
** <span lang="en" dir="ltr" class="mw-content-ltr">The SQL query must be totally ordered.</span> <span lang="en" dir="ltr" class="mw-content-ltr">In other words, the query must be using all columns of some unique key either as constants in the <code>WHERE</code> clause or in the <code>ORDER BY</code> clauses.</span> |
||
| Line 26: | Line 29: | ||
<pre> |
<pre> |
||
(column_0 > value_0 OR (column_0 = value_0 AND |
(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 32: | Line 39: | ||
<span lang="en" dir="ltr" class="mw-content-ltr">Be sure to avoid SQL injection in the values.</span> |
<span lang="en" dir="ltr" class="mw-content-ltr">Be sure to avoid SQL injection in the values.</span> |
||
<span id="Internal_data_structures"></span> |
|||
== Estructuras de datos internas == |
== Estructuras de datos internas == |
||
* <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 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> |
||
Latest revision as of 08:52, 20 July 2026
| Esta página es parte de la documentación de la API de acciones de MediaWiki. |
This explains the implementation of the MediaWiki API machinery in core. If you want to provide an API in your code for clients to consume, read API:Extensiones.
Estructura de archivo/módulo
api.phpis the entry point, located in the wiki root. See API:Main page#Endpoint.ApiEntryPointis the implementation of the entry point (factored out in Gerrit change 959047).includes/apiwill contain all files related to the API, but none of them will be allowed as entry points.- All API classes are derived from a common abstract class
ApiBase. The base class provides common functionality such as parameter parsing, profiling, and error handling. ApiMainis the main class instantiated byApiEntryPoint. It determines which module to execute based on theaction=XXXparameter.ApiMainalso creates an instance of theApiResultclass, which contains the output data array and related helper functions. Lastly,ApiMaininstantiates the formatting class that will output the data fromApiResultin XML/JSON/PHP or other format to the client.- Any module derived from
ApiBasewill receive a reference to an instance of theApiMainduring instantiation, so that during execution the module may get shared resources such as the result object.
Módulos de consulta
ApiQuerybehaves similar toApiMainin that it executes submodules. Each submodule derives fromApiQueryBase(exceptApiQueryitself, which is a top-level module). During instantiation, submodules receive a reference to the ApiQuery instance.- All extension query modules should use a 3 or more letter prefixes. The core modules use 2 letter prefixes.
ApiQueryexecution plan:- Get shared query parameters
list/prop/metato determine needed submodules. - Create an
ApiPageSetobject and populate it from thetitles/pageids/revidsparameters. Thepagesetobject contains the list of pages or revisions that query modules will work with. - If requested, a generator module is executed to create another
ApiPageSet. Similar to the piping streams in UNIX. Given pages are the input to generator that produces another set of pages for all other modules to work on.
- Get shared query parameters
- Requirements for query continuation:
- The SQL query must be totally ordered. In other words, the query must be using all columns of some unique key either as constants in the
WHEREclause or in theORDER BYclauses. - The SQL query must not filesort.
- The value given to
setContinueEnumParameter()must include all the columns in theORDER BYclause. - When continuing, a single compound condition should be added to the
WHEREclause. If the query hasORDER BY column_0, column_1, column_2, this condition should look something like this:
- The SQL query must be totally ordered. In other words, the query must be using all columns of some unique key either as constants in the
(column_0 > value_0 OR (column_0 = value_0 AND (column_1 > value_1 OR (column_1 = value_1 AND (column_2 >= value_2) )) ))
Of course, swap ">" for "<" if your ORDER BY columns are using DESC.
Be sure to avoid SQL injection in the values.
Estructuras de datos internas
- Query API has had very successful structure of one global nested
array()structure passed around. 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). For the API, we suggest wrapping this array as a class with helper functions to append individual leaf nodes.
Error/status reporting
For now we decided to include error information inside the same structured output as normal result (option #2).
For the result, we may either use the standard HTTP error codes, or always return a properly formatted data:
- Using HTTP code
void header( string reason_phrase [, bool replace [, int http_response_code]] )
The header() can be used to set the return status of the operation.
We can define all possible values of the reason_phrase, so for the failed login we may return code=403 and phrase="BadPassword", whereas for any success we would simply return the response without altering the header.
Pros: It's a standard. 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. 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.
Cons: ...
- Include error information inside a proper response
This method would always return a properly formatted response object, but the error status/description will be the only values inside that object. This is similar to the way current Query API returns status codes.
Pros: HTTP error codes are used only for the networking issues, not for the data (logical errors). We do not tied to the existing HTTP error codes.
Cons: If the data format parameter is not properly specified, what is the format of the output data? Application has to parse the object to know of an error (perf?). Error checking code will have to be on both the connection and data parsing levels.
Boilerplate code
Se ha sugerido que esta página o sección se fusione con API:Extensions#ApiSampleApiExtension.php.(Discusión) |
| Simple API module |
|---|
<?php
class Api<module name> extends ApiBase {
public function __construct( $main, $action ) {
parent::__construct( $main, $action );
}
public function execute() {
}
public function getAllowedParams() {
return array(
'<parameter name>' => array(
ApiBase::PARAM_TYPE => array( 'foo', 'bar', 'baz' ),
),
);
}
public function getParamDescription() {
return array(
'<parameter name>' => '<parameter description>',
);
}
public function getDescription() {
return '<Module description here>';
}
public function getExamples() {
return array(
'api.php?action=<module name>&<parameter name>=foo'
);
}
public function getHelpUrls() {
return '';
}
}
|