Page MenuHomePhabricator

[BLOCKED] REST: Beta Modules - automatic discovery with config override
Closed, DeclinedPublic

Description

tl;dr

  • make all REST modules available and published in the REST Sandbox by default
  • add a config variable to override this in cases where it is not desired
NOTE: See T392149: [SPIKE] Research pattern for implementing 'beta' modules for full proposal and links to proof-of-concept changes.

Context

We seek to implement substantial improvements to our APIs over the next year (or more). This includes introducing new standardized patterns for how to build and structure API experiences, introducing new capabilities through API interfaces, and updating existing endpoints to follow the new structures. In many cases, these changes will be relatively high risk, with the expectation that they must remain stable once officially released.

We therefore need to create repeatable mechanisms that will enable easier and more consistent API experimentation. We propose code changes and conventions for "Beta" modules as the first step in achieving this. The overall plan for experimentation support includes changes to module paths and versions, testing patterns, and module registration/discoverability/configuration.

Today, experimentation is done in a haphazard manner across a limited set of teams. In many cases, the experimental state is only stated in documentation, which leads to some adoption in production applications.

Currently, making a new REST API module in core available to callers and visible in the REST Sandbox requires changes to two different configuration variables, and an associated config deploy. These extra steps unnecessarily complicate introduction and removal of experimental modules.

Description

Activating core modules via config is inconvenient and requires either deploy privileges (and the ability/confidence to use it), or scheduling for a deploy window. We've allowed activating extension endpoints/modules for some time without a config change, so there seems to be no process/policy/procedure reason to require it - it is just a consequence of our initial implementation.

Also, the current system requires core developers who wish to both activate their module and publish it to the REST Sandbox to modify two different config variables of different format. And extension developers have to do a config deploy to publish their modules in the REST Sandbox, which seems inconsistent and unnecessary - why should providing documentation be gated through a config deploy, when making the endpoint available in the first place is not?

However, for all its inconvenience, config is useful and powerful. The ability to control whether or not a module is enabled/published on a per-wiki basis is needed for WMF production (and is already being used today). Generally speaking, the system should make it easy to do the normal thing, while still allowing doing less common things when needed. It is okay if less common things require a reasonable amount of additional effort/inconvenience.

This leads to the following:

  • endpoints for all modules (both experimental and non-experimental) are by default available and published in the REST Sandbox
  • modules can be hidden from the REST Sandbox or disabled (their endpoints made unavailable) by a config change
  • the config change to disable/hide a module does not depend on the existence of that module (so that you can deploy the config first, then the code, thereby avoiding a race situation where the endpoints are briefly present)

Implementation

The above has two notable consequences:

  • enabling modules by default means that core modules must be automatically discoverable
  • we don't already have a config variable that would allow disabling an otherwise-available module, or hiding a module from the REST Sandbox that would otherwise appear there. So changes to our config approach will be necessary

There are are several ways we could go about making core modules discoverable, including:

  1. move module definition files into a specific directory, which core will scan at execution time (and cache the results)
  2. introduce a listing file, probably json, that points at module definition files
  3. use config defaults for core, given that core already knows about its own endpoints

#1 is simple for endpoint developers, and makes it easy to see all core module definition files (right now, they're mixed with other files in includes/Rest, which has always felt messy to the author of this task).
#2 feels like configuration within code, adds another thing for developers to remember to do, and introduces a new schema definition.
#3 is literally configuration within code, and adds a non-obvious thing for developers to do outside the Rest directory - modifying config defaults when making a code change isn't a typical pattern

We will therefore do #1. Efficient caching is essential.

For developers who need to disable/hide modules on a per-wiki basis, introduce a new config variables, "RestModuleOverride". This allows overriding the values detected from the module definition file. For example:

$wgRestModuleOverride['mymodule.v1-beta.json'] = [
	'enable' => false,
	'publish' => false
];

The existing config variables are still needed, at least for now. wgRestAPIAdditionalRouteFiles will continue to be used for includes/Rest/coreDevelopmentRoutes.json. wgRestSandboxSpecs will be useful for the default module (until all endpoints are in modules and the legacy ones are removed), but will also continue to be useful if we want to point the Rest Sandbox at things like services outside MediaWiki.

The code should refuse to (attempt to) publish a module that is not enabled. This could be logged at a non-intrusive level, to help identify the erroneous config, but should not display any user-visible error or create excessive logspam.

Future

We also discussed a checkbox allowing the user to choose whether or not they see experimental modules in the REST Sandbox. Or possibly just marking experimental modules in the selection list, maybe by appending "(Experimental)". This would require recognizing experimental modules, presumably the presence of a suffix. And maybe also v0.

None of this is necessary at this time. Given anticipated changes to the REST Sandbox implementation (Swagger UI => Codex), it is difficult to predict the best way that we would go about this. The implementation therefore does not need to make allowences for this.

Event Timeline

Change #1152880 had a related patch set uploaded (by BPirkle; author: BPirkle):

[mediawiki/core@master] REST: Beta Modules - automatic discovery with config override

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

HCoplin-WMF triaged this task as Medium priority.Jun 3 2025, 3:14 PM
HCoplin-WMF set the point value for this task to 5.
BPirkle removed the point value 5 for this task.Jun 3 2025, 4:30 PM

After some conversation with the team, there are concerns about directory scanning.

Here is section of the task description discussing the alternatives that were considered:

There are are several ways we could go about making core modules discoverable, including:

  1. move module definition files into a specific directory, which core will scan at execution time (and cache the results)
  2. introduce a listing file, probably json, that points at module definition files
  3. use config defaults for core, given that core already knows about its own endpoints

#1 is simple for endpoint developers, and makes it easy to see all core module definition files (right now, they're mixed with other files in includes/Rest, which has always felt messy to the author of this task).
#2 feels like configuration within code, adds another thing for developers to remember to do, and introduces a new schema definition.
#3 is literally configuration within code, and adds a non-obvious thing for developers to do outside the Rest directory - modifying config defaults when making a code change isn't a typical pattern

There are probably a lot more alternatives.

In order to keep the hypothesis on track, we need to decide on an approach pretty quickly. I've scheduled sync discussion, but everyone's schedule's are packed and there's little overlap, so it is unlikely everyone who wants to contribute to the discussion can attend. Feel free to discuss async in the comments here, especially if you can't attend the sync meeting, so that your feedback can be part of the conversation.

I suppose the absolute simplest thing for enabling core modules is just to hard-code the module names, in the same way we already hard-code coreRoutes.json. This would make the first part of EntryPoint::getRouteFiles() look like this:

	private static function getRouteFiles( $conf ) {
		global $IP;
		$extensionsDir = $conf->get( MainConfigNames::ExtensionDirectory );
		// Always include the "official" routes. Include additional routes if specified.
		$routeFiles = array_merge(
			[
				'includes/Rest/coreRoutes.json',
				'includes/Rest/content.v1.json',
				'includes/Rest/specs.v0.json',
			],
			$conf->get( MainConfigNames::RestAPIAdditionalRouteFiles )
		);

Alternatively, we could make the array of core route files a private constant near the top of the file, which would be a little more visible.

I tried out the hard-coding change as patch set 2. We can change again if we need to, but figured it'd be easier to evaluate with code to look at.

Summary of sync meeting:

  • we like the hard-coding change for discovery. So discovery will not technically be "automatic" - developers will need to add an entry to the hard-coded array. This seems a small burden, and straightforward for people already making changes to core.
  • we see a need for a config variable to suppress modules on a per-wiki basis. This is along the idea of the RestModuleOverride config variable described in the task description, but can perhaps be a little simpler.
  • for module discovery in the REST Sandbox, we're going to pursue the idea of a RestModuleManager, similar to the existing Action API ApiModuleManager. The idea is to encapsulate the logic surrounding which modules are active, including the logic of which may be suppressed by the config variable. This information will be needed in both Router and SpecialRestSandbox, so putting it into an easily-instantiated class with minimal dependencies seems useful. But we are not entirely sure how this will play out, so it is possible we'll try it, hate the idea, and have to revisit this choice.

I'll put together a change in gerrit for review and further comment.

Change #1155275 had a related patch set uploaded (by BPirkle; author: BPirkle):

[mediawiki/core@master] REST: Beta Modules - automatic module activation/publishing

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

Change #1152880 abandoned by BPirkle:

[mediawiki/core@master] REST: Beta Modules - automatic discovery with config override

Reason:

Abandoning in favor of https://gerrit.wikimedia.org/r/c/mediawiki/core/+/1155275

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

Update:

I did not add a REST Module Manager in the proposed change. I experimented with it in the abandoned change, and decided that doing the way I'd like was a larger refactor than made sense for this task.

That may still be a good idea in the future, because it bothers me that getting information about a module requires all the same dependencies to be injected as executing that module would, when some of them should be unnecessary. But we're mixing dependencies necessary for getting information about things with dependencies necessary for executing them in other places (Handler, Router), so unwinding that isn't a small change. May still be worthwhile, but deserves its own task.

We need to be careful with deployment. If we merged it as-is right now, and it rode the train before we made config changes, then the specs.v0 and content.v1 modules, as well as the REST Sandbox, would become available on all wikis, and we don't want that.

My thoughts on deployment are one of:

  • add the new override config variable to the config repo and deploy that in advance of merging the core change. I think nothing will break if I add a config variable that doesn't exist in core, but I've never done it. So I'm not sure what would happen, or if that's frowned upon
  • break the patch up into two, one to introduce the override and a dependent patch for automatic activation/publishing

The second one is probably a better idea, but I'm open to suggestions.

(I also posted some of the above in Slack)

Change #1162919 had a related patch set uploaded (by BPirkle; author: BPirkle):

[operations/mediawiki-config@master] REST: Introduce new RestModuleOverride config value.

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

HCoplin-WMF renamed this task from REST: Beta Modules - automatic discovery with config override to [BLOCKED] REST: Beta Modules - automatic discovery with config override.Aug 26 2025, 3:30 PM
HCoplin-WMF moved this task from Backlog to To Refine on the MW-Interfaces-Team board.

Do we still need this ticket? Or do you plan to recreate/reshape stuff in response to the other audiences work?