Page MenuHomePhabricator

Create the first extension MW REST API module
Closed, ResolvedPublic8 Estimated Story Points

Description

Description

To promote MW REST API API module creation, we need to have an initial example. Going through the extension module creation process ourselves will also highlight opportunities to make the configuration process easier for API owning teams.

NOTE: Which extension module is selected depends on: https://phabricator.wikimedia.org/T414469

Conditions of acceptance

  • Migrate at least one extension into a dedicated module (proposed, based on T414469: [SPIKE] Determine the most heavily installed and used extensions across Wikimedia installations with REST endpoints; pending feedback on additional audience modules) extension to be its own module.
    • Module appears in the discovery doc
    • Module appears in the the REST Sandbox (within the dropdown, and with docs when selected)
  • Lightly document the current set up process. Assume that this artifact is predominately for MediaWiki Interfaces review and utilization (for now).
    • Identify pain points in the configuration and deployment process, as it exists today.
    • Proposed improvements for pain points.
  • Demo current setup process with the MWI team.
  • Review identified pain points and potential fixes with the MWI team.
    • Create follow up tasks as needed, once we are aligned on the problems and proposed solutions.

Out of scope:

  • For now, do not worry about making the spec fully linter compliant. We can have a follow up task to raise the bar on the quality of the generated spec, likely in partnership with the owning team.

Event Timeline

BPirkle renamed this task from Create the first extension API module to Create the first extension MW REST API module.Jan 13 2026, 2:51 PM
BPirkle updated the task description. (Show Details)
HCoplin-WMF triaged this task as High priority.
OWresch-WMF set the point value for this task to 8.Jan 27 2026, 4:19 PM

Change #1236409 had a related patch set uploaded (by Aaron Schulz; author: Aaron Schulz):

[mediawiki/extensions/GrowthExperiments@master] [WIP] Introduce a REST module for /growthexperiments/v0 endpoints

https://gerrit.wikimedia.org/r/1236409

Change #1236409 merged by jenkins-bot:

[mediawiki/extensions/GrowthExperiments@master] Introduce a REST module for /growthexperiments/v0 endpoints

https://gerrit.wikimedia.org/r/1236409

Change #1242538 had a related patch set uploaded (by Aaron Schulz; author: Aaron Schulz):

[mediawiki/extensions/GrowthExperiments@master] Tweak rest-module-growthexperiments.v0-title for consistency

https://gerrit.wikimedia.org/r/1242538

Change #1242613 had a related patch set uploaded (by Aaron Schulz; author: Aaron Schulz):

[operations/mediawiki-config@master] [DNM] Add growthexperiments.v0 to $wgRestSandboxSpecs

https://gerrit.wikimedia.org/r/1242613

Change #1242743 had a related patch set uploaded (by Aaron Schulz; author: Aaron Schulz):

[mediawiki/extensions/GrowthExperiments@master] [DNM] Remove redundant flat REST routes (e.g. "RestRoutes")

https://gerrit.wikimedia.org/r/1242743

Change #1242538 merged by jenkins-bot:

[mediawiki/extensions/GrowthExperiments@master] Tweak rest-module-growthexperiments.v0-title for consistency

https://gerrit.wikimedia.org/r/1242538

Here are the current generic steps I'm going through with GrowthExperiements:

  1. Make sure you locally enable DevelopmentSettings.php so that specs endpoints and the Special:RestSandbox special page work. The old flat routes should listed at rest.php/specs/v0/module/-.
  2. Locally, the existing unit tests and api-testing integration tests should work locally as a reference point. Adds some if needed, making a stand-alone patch to base the actual module patches on.
  3. Look at the extension's current flat routes files (referenced from "RestRoutes" in extension.json). Find the path prefix, in the form of "/<module_name>/v<major_version>", that corresponds to what should be a module. For example, "/growthexperiments/v0" might correspond to what should be a module ID (e.g. "growthexperiments/v0").
  4. Make a patch adding the module definition file named "<moduleId_without_version>.v<moduleId_major_version>.json". This is sometimes called the "module spec" . Update extension.json to include "RestModuleFiles": [ "<path_to_module_definition_file_relative_to_the_extension>"] (e.g. use "includes/Rest/growthexperiments.v0.json"). Leave the old "RestRoutes" redundant values in place, the module routes will take precedence.
    1. Make sure the file defines all the routes and i18n- message keys and looks like it meets the newest mw-api schema under includes/docs/rest/ (e.g. "mw-api-1.1.json" at the time of this writing). See includes/Rest/growthexperiments.v0.json" from GrowthExperiments as an example.
    2. Make sure that the old flat routes are still listed at rest.php/specs/v0/module/-.
    3. Make sure the new specs appear at rest.php/specs/v0/discovery.
    4. Make sure that the new specs appear at rest.php/specs/v0/module/<moduleId_without_version>/<moduleId_major_version> (e.g. "rest.php/specs/v0/module/growthexperiments/v0"). This is the module's API spec (not to be confused with the "module spec" mentioned above). Create any messages that appear as placeholders (make the en.json and qqq.json files and update "MessagesDirs" in extension.json as needed). Make sure that the 'rest-module-<moduleId_without_version>.<moduleId_major_version>-title' message, in English, says something like "Such-and-such API" (e.g. "Growth experiments API"). It's probably a good idea to use a Rest/ subdirectory for such messages instead of mixing them with a huge grab-bag of messages for the extension. You might need to clear APCu or run rebuildLocalisationCache.php after adding new messages.
  5. Locally, set $wgRestSandboxSpecs["<moduleId_without_version>.v<moduleId_major_version>.json"] to an array with 'url' set to "$wgScriptPath/rest.php/specs/v0/module/<moduleId_without_version>/<moduleId_major_version>" and 'msg' to 'rest-module-<moduleId_without_version>.<moduleId_major_version>-title'. The Special:RestSandbox page should show a working dropdown for the new module.
    1. The phpunit and api-testing tests should pass, since they map to handlers doing the same thing. Note that core will structure test the new module definition files for validity in testModuleDefinitionFiles.
    2. You can paste the pretty-printed output of rest.php/specs/v0/module/<moduleId_without_version>/<moduleId_major_version> into https://apinotes.io/openapi-validator to lightly validate the output. You can also paste it into https://wmf-openapi-linter.toolforge.org/ to check for our org-specific rules. Many of the issues might simply carry over from the original flat module API specs, and they might be numerous...this is best left as separate follow-up work.
  6. Make a similar CommonSettings.php patch in the mediawiki-config repo that sets the wgRestSandboxSpecs key right after the relevant wfLoadExtension() call. This will add a dropdown for the module at the RestSandbox page, with the flat routes still remaining. Once the flat routes eventually get removed, their specs will disappear. Merge it only after the above extension patches get merged and the deploy train looks stable (a train rollback will make the RestSandbox page show load errors since the module spec URL will fail to load).
  7. Create a patch to remove the old flat routes from the extension. Merge it only after the above CommonSettings.php patch is merged.

The main pain points seem to be:

  • The song and dace of having to do a config change since modules do not get pulled into the RestSandbox automagically. We want to avoid having the endpoints disappear completely from the RestSandbox but also don't want RestSandbox load errors because the module isn't enabled yet. This forces multiple extension commits and a backport deploy, which adds delay, complication, and similar code fragments scattered through config that each "know" something about the extensions moduleId.
    • A more clever way could involve a more conditional config patch that only updates the sandbox specs if the extension is on a version having the module definition file. Within InitialiseSettings.php/CommonsSettings.php, it's too early to use stuff like extension version checks or checking a new constant defined by the extension, as Setup.php has not yet reached ExtensionRegistry::getInstance()->finish(). You could have something in the block with the relevant wfLoadExtension() checking the existence of "$wgExtensionDirectory/my_extension/src/Rest/my_module.v1.json", but that seems ugly and would break if the json file moved. Also, ExtensionProcessor does not support a 'RestSandboxSpecs' field and that variable is marked as experimental anyway.
    • In theory, the extension.json could have "callback" set to the name of a static function that updates $wgRestSandboxSpecs (though it's still marked experimental).
    • The current audience proposal at T409517#11563818 would moot this whole issue.
  • Having to mess around with module spec caching and localization caching.

Change #1242613 merged by jenkins-bot:

[operations/mediawiki-config@master] Add growthexperiments.v0 to $wgRestSandboxSpecs

https://gerrit.wikimedia.org/r/1242613

Mentioned in SAL (#wikimedia-operations) [2026-03-02T22:03:22Z] <aaron@deploy2002> Started scap sync-world: Backport for [[gerrit:1242613|Add growthexperiments.v0 to $wgRestSandboxSpecs (T414470)]]

Mentioned in SAL (#wikimedia-operations) [2026-03-02T22:05:11Z] <aaron@deploy2002> aaron: Backport for [[gerrit:1242613|Add growthexperiments.v0 to $wgRestSandboxSpecs (T414470)]] synced to the testservers (see https://wikitech.wikimedia.org/wiki/Mwdebug). Changes can now be verified there.

Mentioned in SAL (#wikimedia-operations) [2026-03-02T22:10:02Z] <aaron@deploy2002> Finished scap sync-world: Backport for [[gerrit:1242613|Add growthexperiments.v0 to $wgRestSandboxSpecs (T414470)]] (duration: 06m 39s)

By making the CommonSettings.php patch in mediawiki-config similar to https://gerrit.wikimedia.org/r/c/operations/mediawiki-config/+/1242613 , a single extension repo patch can be made to migrate the extension from flat routes to a module, instead of two. The config patch should be deployed first, with the extension patch riding the train later.

The new process becomes:

  1. Make sure you locally enable DevelopmentSettings.php so that specs endpoints and the Special:RestSandbox special page work. The old flat routes should listed at rest.php/specs/v0/module/-.
  2. Locally, the existing unit tests and api-testing integration tests should work locally as a reference point. Adds some tests if needed, making a stand-alone patch to base the actual module patches on.
  3. Look at the extension's current flat routes files (referenced from "RestRoutes" in extension.json). Find the path prefix, in the form of "/<module_name>/v<major_version>", that corresponds to what should be a module. For example, "/growthexperiments/v0" might correspond to what should be a module ID (e.g. "growthexperiments/v0").
  4. Make a patch adding the module definition file named "<moduleId_without_version>.v<moduleId_major_version>.json". This is sometimes called the "module spec" . Update extension.json to include "RestModuleFiles": [ "<path_to_module_definition_file_relative_to_the_extension>"] (e.g. use "includes/Rest/growthexperiments.v0.json"). Remove the old "RestRoutes" redundant values.
    1. Make sure the file defines all the routes and i18n- message keys and looks like it meets the newest mw-api schema under includes/docs/rest/ (e.g. "mw-api-1.1.json" at the time of this writing). See includes/Rest/growthexperiments.v0.json" from GrowthExperiments as an example.
    2. Make sure that the old flat routes are no longer listed at rest.php/specs/v0/module/-.
    3. Make sure the new specs appear at rest.php/specs/v0/discovery.
    4. Make sure that the new specs appear at rest.php/specs/v0/module/<moduleId_without_version>/<moduleId_major_version> (e.g. "rest.php/specs/v0/module/growthexperiments/v0"). This is the module's API spec (not to be confused with the "module spec" mentioned above). Create any messages that appear as placeholders (make the en.json and qqq.json files and update "MessagesDirs" in extension.json as needed). Make sure that the 'rest-module-<moduleId_without_version>.<moduleId_major_version>-title' message, in English, says something like "Such-and-such API" (e.g. "Growth experiments API"). It's probably a good idea to use a Rest/ subdirectory for such messages instead of mixing them with a huge grab-bag of messages for the extension. You might need to clear APCu or run rebuildLocalisationCache.php after adding new messages.
  5. Locally, to your config, add code that checks is_file() on the new module definition file to set $wgRestSandboxSpecs["<moduleId_without_version>.v<moduleId_major_version>.json"] to an array, having just one key, 'file', set to "$wgExtensionDirectory/<extension_name>/path/to/<moduleId_without_version>.v<moduleId_major_version>.json". Here is an example patch. The Special:RestSandbox page should show a working dropdown for the new module.
    1. The phpunit and api-testing tests should pass, since they map to handlers doing the same thing. Note that core will structure test the new module definition files for validity in testModuleDefinitionFiles.
    2. You can paste the pretty-printed output of rest.php/specs/v0/module/<moduleId_without_version>/<moduleId_major_version> into https://apinotes.io/openapi-validator to lightly validate the output. You can also paste it into https://wmf-openapi-linter.toolforge.org/ to check for our org-specific rules. Many of the issues might simply carry over from the original flat module API specs, and they might be numerous...this is best left as separate follow-up work.
  6. Make a similar CommonSettings.php patch in the mediawiki-config repo that conditionally sets the wgRestSandboxSpecs key right after the relevant wfLoadExtension() call. Once the module patch is deployed, the flat route specs will disappear and get replaced by the module specs. Until then, the flat routes will remain in the REST sandbox.
  7. Deploy the mediawiki-config patch before the extension patch gets rolled out so the routes never go missing from the sandbox. It might help to mark the extension patch as DNM until the config patch is merged.

Change #1242743 merged by jenkins-bot:

[mediawiki/extensions/GrowthExperiments@master] Remove redundant flat REST routes (e.g. "RestRoutes")

https://gerrit.wikimedia.org/r/1242743