Page MenuHomePhabricator

[SPIKE] Research pattern for implementing 'beta' modules
Closed, ResolvedPublic2 Estimated Story Points

Description

Description

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, including establishing standard communication pathways with our technical volunteer communities. We propose including a new 'vBeta' indicator in our routing structure so that it is obvious to developers that the endpoints are in a test phase. The scope of this work will be exploring how to implement that pattern in a repeatable way, including surfacing beta specific modules within the REST Sandbox so that users may discover, interact with, and ultimately provide feedback on the new endpoints.

Conditions of acceptance

This is a research task. Investigate the best approach for the following items:

  • Any module can have a 'beta' version, as represented by {modulename}/vbeta/{endpoint} (but not every module will have a beta version, if there is no active beta testing happening)
  • 'beta' modules co-exist with the production version of that module. They are defined separately and only contain endpoints that have an active beta version.
  • Determine pattern for unit & integration testing naming patterns. With this pattern, there may be two (or more) versions of these tests, depending on the endpoint version.
  • Experiment with easier beta registration -- ideally a config deployment is not required to add a 'beta' module.
  • Determine a mechanism for including a 'feedback' page on every beta module. This link should be included in the spec, appear in the Sandbox, and have a process for verifying that the page exists.
  • Create tickets to implement the items above.

Implementation details

There are other approaches/patterns for API versioning, including for experimental or unstable endpoints. Today, experimentation is done in a haphazard manner across a limited set of teams. For example, the Enterprise team recently introduced the notion of “beta” endpoints (see: Article structured content at the time of this writing). Similarly, the RESTbase APIs have a notion of endpoint stability indicators on their endpoints. However, in both cases, the experimental state is only stated in documentation, which leads to some adoption in production applications.

There is also a pattern where 'v0' indicates that an endpoint is 'unstable'. The existing 'unstable' pattern indicates that the endpoint may change over time, but does not make guarantees for when or how frequently. This can result in unexpected breaking changes when unstable endpoints are used in production applications, which is a frequent occurrence. The proposed 'vBeta' sends a stronger signal about the frequency of change and limited lifespan of the endpoint. Specifically, beta endpoints will change frequently during the beta period as we respond to feedback, and may be either deprecated or elevated to an official version after the beta period is over. Once elevated to a stable version, they will be locked into the stable version policy.

Event Timeline

HCoplin-WMF updated the task description. (Show Details)
HCoplin-WMF set the point value for this task to 5.

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

[mediawiki/core@master] REST: exploratory changes for beta modules. Will be abandoned.

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

What follows is a lengthy and rather opaque technical analysis. To save some reading for anyone who doesn't care about the details, here's the tl;dr for my recommendations:

  • tweak the regex in Router.php to allow strings instead of just digits after the "v" in the version part of module ids
  • encourage beta modules to use "vbeta" in paths, moduleId values, and message keys.
  • continue to use semantic versioning (ex. 0.1.0) for the "version" string in module definition files
  • place integration tests in directories named for the module. For example: tests/api-testing/REST/mymodule. This means renaming the current tests/api-testing/REST/content.v1 to just tests/api-testing/REST/content, and adjusting the associated Legacy tests. Modules that wish to divide tests by module version can do so via either separate file names or separate subdirectories.
  • add support for "enabled" and "published" keys to module definition files to enable/disable endpoints and publish them (or not) to the REST Sandbox.
  • add an "override" config variable, allowing the enabled/published values from module definition files to be overridden by config on a per-wiki basis. Make sure to modules defined in both core and extensions. The current config values are still needed, at least for now
  • smoothly transition the existing content.v1 and specs.v0 modules to the new system (keeping in mind that production config refers to their current locations)
  • talk more as a team about feedback - that part is thorny

Option: we could tweak the Router.php regex such that it allowed v# (letter "v" followed by digits) or "vbeta", but disallowed any other strings. This would more tightly enforce the convention we're proposing by allowing "vbeta" but disallowing whatever other random things people might decide to try ("vdev" "vinternal, etc.). We can discuss whether we prefer to allow such experimentation or not.

Question: do we need to create an mwapi-1.1 with enabled/published as optional parameters that, if present, must be boolean?

Question: I called the new fields "enabled" and "published" because it was my first instinct. But should that just be "enable" and "publish"?

Now the long version:

Paths/Ids

From a technical point of view, a module is (currently) identified by the unique combination of name and version. In other words, from the perspective of the MW REST API infrastructure code, there is no concept that mymodule.v1 and mymodule.v2 are different versions of the same module. They're just two different strings that identify two different modules. This works to our advantage here, as there's less technical baggage.

Module names are currently expected to follow a certain pattern, specifically:

  • private const PREFIX_PATTERN = '!^/([-_.\w]+(?:/v\d+)?)(/.*)$!';

This essentially says that, to be recognized as a module for the purpose of matching a path to a handler via module definition files, this portion of the path must look like:

  • something/vnumber

Where "something" is an arbitrary string and "number" is digits. So really, the only requirement on module names right now is that a module name portion exists, and the version portion is a "v" followed by some numbers.

This is checked in the Router class, and allows the MW REST API infrastructure to identify that a particular path belongs to a module (as opposed to being a legacy route from before the module system existed).

We tend to call modules things like "mymodule.v1", but in the path and the moduleId in the module definition file we use a forward slash rather than a period to separate the name and version portions. So "mymodule.v1" appears in paths and module definition files as "mymodule/v1". The module definition file names use the period form (because slashes in file names are problematic). For example, the file content.v1.json contains a moduleId of "content/v1".

Module Versions

Module definition files include a "version" key (within the "info" block, required by the OpenAPI spec for info blocks). It will show up in the REST Sandbox in a small bubble by the module name. It already accepts strings, so no technical changes are needed. However, some conventions would be helpful. Should beta modules just put "beta" for the version? What if beta modules want to alert callers via the spec that changes were made? This seems useful and polite. What about something like 0.1.0 / 0.1.1? Or beta-0.1.0 / beta-0.1.1?

  • I prefer the 0.1.0 pattern, because clients may already be set up to recognize [[ https::semver.org | semantic versioning ]]. The benefit of "vbeta" is really in the path, for visibility, not in the version string.

Things I observed when setting this up:

  • I went with "vbeta" rather than "vBeta" everywhere. mostly because it is really annoying having to remember whether to type "vbeta" or "vBeta". Certain things (message keys, for instance) are all lower case by convention. This mostly just matters when setting up a beta module in the first place, not for maintaining the endpoints over time. So it isn't *that* big a deal if we prefer mixed case. But I started with mixed case in the path, and it having to keep up with which to type bothered me enough to make me change my mind.
  • our current convention is to include the url form of the module version from the url in module title/desc message keys. For example, "rest-module-content.v1-title" instead of just "rest-module-content-title". That's probably preferable, as it give flexibility to call out that something is beta, or to change the module name across versions. But it does increase the number of translatable strings.

Testing

Module-level testing at the module level is performed only at the mocha (true integration test) level. Unit testing (whether via tests under phpunit/integration/includes/Rest or phpunit/unit/includes/Rest) exercises the Handler-derived classes, not the modules (which are not PHP classes and are therefore not unit testable in this way). And we apply no conventions on how beta vs release version of modules arrange their handlers, because that is very situational.

Looking at mocha testing, while different versions of a module are, technically speaking, completely different modules that aren't required to have anything in common, they will frequently be very similar. This means there will often be opportunity to share testing functions, or maybe even entire tests.

We can support this by convention by placing the tests for each module in a directory named by the pre-version portion of its module name. For example, "content" or "specs".This means renaming the current tests/api-testing/REST/content.v1 to just tests/api-testing/REST/content. This prevents proliferation of testing directories (which isn't a technical limitation - lots of directories is fine - but it does get unwieldy to read).

More importantly, it gives each module a place to arrange tests in the most convenient way for its own needs within that directory. Modules that wish to divide tests by module version can do so via either separate test file names or separate directories under the module test directory. Modules that wish to place tests for all versions in the same test files may do so.

For example, a module with complex and dramatically different testing needs across versions might choose to have something like:

mymodule
-- vbeta
----- FileWithTests.js
----- OtherFileWithTests.js
-- v1
----- DifferentFileWithTests.js
----- AnotherDifferentFileWithTests.js

A different module with simpler and more similar testing needs across versions might have:

mymodule
-- FileWithBetaTests.js
-- FileWithV1Tests.js
-- Common.js

And a module with very similar testing needs across versions might simply have:

mymodule
-- FileWithTests.js

Registration

Activating beta modules via config is inconvenient and requires either deploy privileges (and the ability/confidence to use it), or scheduling for a deploy window. Also, the current system requires developers who wish to both activate their module and publish it to the REST Sandbox to modify two different config variables of different format. (This all true of regular release modules as well, so any improvements we make here would benefit all REST API developers, not just those using beta modules).

However, for all its inconvenience, config is useful and powerful. The ability to enable/disable or publish modules on a per-wiki basis is essential for WMF production (and is already being used today).

To make this more convenient, we can support two new boolean keys in module definition files:

  • enabled: if true, endpoints for the module are available to be called
  • published: if true, endpoints for the module will be available for viewing in the REST Sandbox

There is no facility to enable/disable or publish/not publish endpoints on a per-endpoint basis, just a per-module basis. That's consistent with current behavior.

This will cover many needs, allowing developers to introduce beta modules without a config change. For many usages, and for most third parties, this is should be sufficient.

For developers who need to manage these settings on a per-wiki basis, introduce a new config variables, "RestModuleOverride". This allows overriding the values from the module in config. For example:

// Illustrates the ability for these config variables to override module definition file
$wgRestModuleOverride['mydisabledmodule.v1.json'] = [
	'enabled' => true,
	'published' => true
];

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.

Feedback Mechanism

Part of this are tricky, for reasons that I'm not sure we can resolve in code. The task description says:

  1. the feedback link should be included in the spec
  2. the feedback link should appear in the REST Sandbox
  3. there should be a process to ensure the page being linked to exists

For #1, Open API specs allow for "extensions", which are just custom properties starting with "x-". We're already going to use this for things like x-i18n-description. So we can just toss something like x-feedback-link (or whatever we call it) into the info portion of the module definition file and it'll show up in the spec.

Alternatively, if we see ourselves making more of these things, we could make something like an x-mediawiki block and put our various x-whatever properties in there.

For #2, though, displaying the feedback link is problematic. The swagger ui docs mention a showExtensions config value that "Controls the display of vendor extension (x-) fields and values for Operations, Parameters, Responses, and Schema". None of those places are at the top level where we need it. Experimentation at https://editor.swagger.io/ confirms that adding an x-whatever property within and endpoint (for example, just under the "get" property) causes it to show in the displayed docs, but adding it where we'd like to does not.

An interim solution might be to put the feedback link into the module description, and consider support x- extensions in the Codex version of the REST Sandbox, where hopefully we can do it more cleanly.

Alternatively, we could add custom code to display this on the REST Sandbox page similar to how we handle the module selection form and the disclaimer. That feels a little bespoke vs proper support for reading it from the spec in the portion of the page that's meant to to that, but it would be possible.

The last part - ensuring the page being linked to exists - is even more problematic. I can't think of a great way to do this from within MediaWiki code. Tests don't have access to production databases, nor can they call external links. And this needs to work for third party MW installations too. Automated creation of regular pages could be limited by a particular wiki's configuration. It might be possible to create a Feedback special page that handles feedback on a per-module basis. There's also a VisualEditor Feedback page we could look at for inspiration.

Of course the word "process" in the portion of the task description about confirming the feedback page exists could be interpreted to be a human process and not an automated one. In that case, we could support it via documentation establishing how developers are expected to create feedback pages.

For an initial solution, my recommendation is to document a policy of adding feedback links to module descriptions, and manually creating feedback pages. Then revisit at least parts of that as we develop a Codex-based replacement for Swagger UI.

References

Some related tasks and patches:
T375899: REST: consider separating "module id" and "module prefix" as separate concepts.
T366567: REST: introduce audience designations (proposal)
T365752: REST: Introduce support for private modules
T232485: RFC: Core REST API namespace and version (this one is really old and not all that relevant, but has some discussion that might be good for context)
REST: Change content.v1 to content/v1 match new conventions

BPirkle changed the point value for this task from 5 to 2.May 20 2025, 3:00 PM

Per discussion with @daniel , the "Registration" section needs more thought. My messy notes from that conversation:

  • Enabling/publishing feels more like the job of configuration than code. The idea of adding flags for this to module definition files therefore seems misplaced.
  • Marking a module as experimental does feel like a reasonable thing to indicate in code, rather than config. It says something about the code, rather than site it executes on.
  • One possible approach: experimental modules are disabled by default, non-experimental modules are enabled by default. Could be overridden in config.
  • Enabling modules currently works differently in core vs extensions. For core, developers must do a separate config deploy. For extensions, the developer merely needs to adjust extension.json. Should this be the case?
  • By default, we could make enabling a module cause it to be published in the REST Sandbox, but give a way via config to hide it if desired
  • We could add a checkbox/setting to the REST Sandbox allowing users to opt in to seeing experimental endpoints. If so, would need to decide how that interacted with the defaults and any config overrides.
  • It is a bit awkward in core to get the url for a module's OpenAPI spec. The common part of the spec path could be a constant, maybe in Module, or related code

I'll revisit that section and come up with an alternate proposal (and maybe PoC patch) for consideration.

It is a bit awkward in core to get the url for a module's OpenAPI spec. The common part of the spec path could be a constant, maybe in Module, or related code

From inside a Handler, you can use:

$specUrl =$this->getRouter()->getRouteUrl( 'specs/v0/module/{module}', [ 'module' => $module ] );

Actually, we already have a constant for the path, so you could use:

$specUrl =$this->getRouter()->getRouteUrl( ModuleSpecHandler::MODULE_SPEC_PATH, [ 'module' => $module ] );

But... we also have specs/v0/discovery, which lists all the modules along with the url of their spec! Do Special:RestSandbox could either call that and use the response, or share code with DiscoveryHandler.

Thanks.

I'd forgotten about MODULE_SPEC_PATH, which is currently unused but may be useful here (if we keep that part).

The exploratory patch is constructing these urls in SpecialRestSandbox, where a Router instance is not available (unless we create one). But that may not be the best way or place for all this. In fact, that code is so embarrassingly bad that I hesitated to even link it. So if we do continue along these lines, a LOT needs to change with that implementation.

I'm going to rethink registration/enabling/publishing first, then see what our implementation needs end up being. It may turn out that none of this is relevant anymore, and not something we have to worry with right now.

I have a few thoughts too:

Option: we could tweak the Router.php regex such that it allowed v# (letter "v" followed by digits) or "vbeta", but disallowed any other strings. This would more tightly enforce the convention we're proposing by allowing "vbeta" but disallowing whatever other random things people might decide to try ("vdev" "vinternal, etc.). We can discuss whether we prefer to allow such experimentation or not.

Suggestion would be to start being more restrictive, with vbeta as the only supported value. It's always easier to add things later than it is to take them away in the wild; although it's unlikely, I would see potential for introducing more confusion if we leave it open for other values. That being said, this is an interesting point for how we could configure audiences more broadly.


Regarding registration

  • Enabling modules currently works differently in core vs extensions. For core, developers must do a separate config deploy. For extensions, the developer merely needs to adjust extension.json. Should this be the case?

Could you clarify this a little bit? Is the primary option adding more friction, where extensions would need to add something to config instead of assuming that if the extension is registered in extension.json and has an API it is ready for publishing? I'm slightly hesitant to add an additional step that extension authors may forget to do.

For what it's worth, I don't think it's inherently bad that they're different. I could see an argument where we want it to be easier for extensions, and that it makes sense that the API would be automatically enabled at the same time as the extension. Core changes seem like they should be less frequent and maybe more impactful, which suggests they should have a bit more gravity to them anyway. I would like to better understand the difference and options though.

  • By default, we could make enabling a module cause it to be published in the REST Sandbox, but give a way via config to hide it if desired

Preference here is we publish and enable new modules by default and do not offer an additional visibility config option at this time. Publishing by default avoids scenarios where a team publishes their module, but forgets the second step of visibility configuration. It also again seems like a scenario where it might be easier to add config options to hide later, if they are necessary, than trying to overcomplicate the flow up front. My preference would also be to include beta options by default.

  • We could add a checkbox/setting to the REST Sandbox allowing users to opt in to seeing experimental endpoints. If so, would need to decide how that interacted with the defaults and any config overrides.

Let's skip this for now too. We have the opportunity to consult with the design team for the codex redesign to see if they have suggestions, and I would err on the side of keeping the beta modules visible until we have reason not to (eg: they're getting used in production, or there are too many simultaneous beta versions running simultaneously).

Paths/Id (alternative idea)

Our pattern of naming modules like mymodule.v1 seems reasonable and follows semantic versioning practices, and the "vbeta" version seems fine for the clean case of beta => v1 => v2. However, it doesn't very well handle situations like a developer wanting to have a beta period on proposed changes to be released as v2 of a module. Such a developer could always just put the proposed endpoints at "vbeta", but (1) it is a non-obvious that this means a proposed v2, especially if the module originally went through a prerelease beta and (2) it locks us into only ever having one beta version of a module active at any particular time. And as hard as it sometimes is to retire/remove things at WMF, that could become problematic.

Instead, we could indicate beta by apprending "-beta" to the module version. Under this model, all of these are possible:

  • mymodule.v0
  • mymodule.v0-alpha
  • mymodule.v0-beta
  • mymodule.v0-rc1
  • mymodule.v0-rc2
  • mymodule.v1-alpha
  • mymodule.v1-beta
  • mymodule.v1-rc1
  • mymodule.v1-rc2
  • mymodule.v1
  • mymodule.v2-alpha
  • mymodule.v2-beta
  • mymodule.v2-rc1
  • mymodule.v2-rc2
  • mymodule.v2

And while it would probably be a bad idea, all of them could exist simultaneously.

Also, we don't need to actually allow all those in the first draft. We could limit the allowed path/id suffixes to "beta". But starting out with a forward-looking pattern that allows future expansion seems desirable.

Module Versions (revised proposal)

Module definition files include a "version" key (within the "info" block, required by the OpenAPI spec for info blocks). It will show up in the REST Sandbox in a small bubble by the module name. It already accepts strings, so no technical changes are needed. However, some conventions would be helpful.

Semantic Versioning 2.0.0 says:

A pre-release version MAY be denoted by appending a hyphen and a series of dot separated identifiers immediately following the patch version. Identifiers MUST comprise only ASCII alphanumerics and hyphens [0-9A-Za-z-]. Identifiers MUST NOT be empty. Numeric identifiers MUST NOT include leading zeroes. Pre-release versions have a lower precedence than the associated normal version. A pre-release version indicates that the version is unstable and might not satisfy the intended compatibility requirements as denoted by its associated normal version. Examples: 1.0.0-alpha, 1.0.0-alpha.1, 1.0.0-0.3.7, 1.0.0-x.7.z.92, 1.0.0-x-y-z.--.

This is quite flexible, so we'll still want our own conventions. But the key point is that prerelease versions are identified by an appended string. This follows the above alternative Paths/Id proposal.

Under this pattern, all of the following are valid version strings, and would be consistent with the revised module id proposal:

  • 0.1.0
  • 0.1.1
  • 0.1.0-alpha
  • 0.1.0-beta
  • 0.1.0-rc1
  • 0.1.0-rc2
  • 1.0.0-alpha
  • 1.0.0-beta
  • 1.0.0-rc1
  • 1.0.0-rc2
  • 1.0.0
  • 1.0.1
  • 1.1.0
  • 2.0.0-alpha
  • 2.0.0-beta
  • 2.0.0-rc1
  • 2.0.0-rc2
  • 2.0.0
  • 2.0.1
  • 2.1.0

Tests (maybe even a structure test) could help ensure the module id and version string are consistent.

As with path/id, we don't have to initially allow any suffix other than "beta". But having our conventions allow for that as a future expansion seems useful.

Registration (revised proposal)

Goals:
  • allow modules to declare themselves as experimental
  • endpoints for experimental modules are by default not available, unless enabled by a config change
  • endpoints for non-experimental modules are by default available, unless disabled by a config change
  • the config change to disable 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 available)
  • all available modules are by default published in the REST Sandbox, unless explicitly overridden to not be published

Note: we also discussed a checkbox allowing the user to choose whether or not they see experimental modules in the REST Sandbox. I'm not including that in the proposal. It could be added separately, later. A simpler interim idea would be to mark experimental modules in the module selection list, maybe by appending "(Experimental)".

Implications:
  • enabling non-experimental modules by default means that modules must be automatically discoverable (somehow)
  • enabling non-experimental modules by default brings core and extension behavior closer - no config change is needed to make new non-experimental core modules available (that's already the case with extensions)
  • having different default behavior between experimental and non-experimental modules means we need a way to tell them apart
  • 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

Alternative: it would be somewhat simpler to make all modules enabled by default. We would not then need a way for experimental and non-experimental modules to differentiate themselves. We'd still need to make modules automatically discoverable, and would still need changes to the config approach to make automatically-enabled modules instead be disabled.

Details:

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 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.

The normal case is that experimental modules should only be available if developers take extra action to make that the case, while non-experimental modules should be available unless developers take extra action to make them unavailable. It is also normal for available modules to be published in the REST Sandbox, unless developers take extra action to make them unpublished.

Making modules available without a config change means that we need some way in core code to make core modules automatically discoverable (extension modules are already automatically discoverable by virtue of being listed in extension.json, and making modules that exist in extension code unavailable is easily achieved by simply not listing them in extension.json). The most obvious ways to make core modules automatically discoverable are:

  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 bothered me a little).
#2 feels to me 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

My biased opinion is #1. That puts a little more burden on us as the MW REST API framework maintainers to implement the discovery code in an efficient way, but that should be a one-time effort.

Varying the behavior between experimental and non-experimental modules without any config changes requires that we have some way to distinguish them, in core code and not in config. Obvious options are:

  1. add a value to module definition files indicating whether or not the module is experimental (something like "experimental": true at the same level as moduleId.
  2. detect whether the module is experimental based on the module version
  3. introduce a listing file, probably json, that indicates on a per-module basis which are experimental and/or which are not
  4. use config defaults (problematic for extensions, which might need a way to indicate this in extension.json)

My arguments against #3 and #4 are similar to above, for automatic discoverability. #1 would be very unambiguous, but moves our module definition files farther from looking like OpenAPI files. #2 might be easier to miss, but would naturally follow the proposed module id and version string approaches above. Effectively, any module whose module id / version string includes a dash would be considered experimental.

I'm planning to explore #2 in the PoC implementation, as a rough example of what that might look like in code.

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

// Illustrates the ability for these config variables to override module definition file
$wgRestModuleOverride['mymodule.v1-beta.json'] = [
	'enable' => true,
	'publish' => true
];
$wgRestModuleOverride['mymodule.v1.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.

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

[mediawiki/core@master] REST: exploratory beta module changes, v2. Will be abandoned.

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

For the updated PoC 2, I went with:

  • all modules enabled by default, not just non-experimental modules (contradicting what I said I would do in the above comment)
  • no checkbox or special marker for experimental modules in the REST Sanbox

Summary of the plan, as it affects developers:

  • The url of beta modules looks like http://localhost:8080/w/rest.php/mymodule/v0-beta/echo.
  • Other legal version portions of urls include v0, v1, v2, v1-beta, v2-beta, and so on
  • The module version string in the module definition file must follow semantic versioning, enforced by a structure test. Ex. 0.1.0, 1.0.0, 2.1.1, 0.3.3-beta, 1.1.0-beta
  • The system will easily extend to other suffixes (-alpha, -rc1, etc.) if we ever want it. But for now, the structure test will only allow -beta.
  • All modules will be enabled and published by default, unless disabled/hidden via config
  • A new config variable will allow explicitly enabling/disabling/publishing/hiding modules. Existing config variables will continue to exist.
  • Place core module definition files in their own directory for automatic discovery (I suggested includes/Rest/Modules/Module, but don't have strong feelings)
  • As a convention (not enforced), put module integration tests in directories named for the base portion of the module (ex. tests/api-testing/REST/mymodule)

Part of the motivation for enforcing semantic versioning in the version string in module definition files is to support things outside the scope of this task. For example, automated changelogs or documentation. All that's a lot simpler if the version strings are consistent, and requiring developers to add .0 to their versions seems a small ask. It is, however, a breaking change and will have to be recognized as such.

The convention around integration test locations supports patterns for reusing tests across all version of modules. This seems like something people will want as modules move from beta to release.

There are a few more little details scattered throughout the proposal, but I think the above is everything we need to agree on before I can proceed with the real changes. Feedback welcome and encouraged.

Oh, and the most recent PoC change does not exactly reflect the above, because I was experimenting. But unless we change the plan, the real changes will.

Change #1141196 abandoned by BPirkle:

[mediawiki/core@master] REST: exploratory changes for beta modules. Will be abandoned.

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