Page MenuHomePhabricator

Action API: prefer the action parameter to be given as a query parameter, even for POST requests
Closed, ResolvedPublic

Description

Proposal: The Action APIs documentation should state that the action parameter should be supplied as a query parameter, even for POST requests. Not doing so should trigger a warning in the response. We should update our own code, in particular mw.Api, to follow this rule.

Motivation: it is useful for instrumentation, rate limiting (T419130), etc for layers sitting in front of MediaWiki to know which action a given request is going to perform.

Note: care must be taken that the action given in the query parameter is not then overwritten in the post body (T421287).

Event Timeline

Atieno triaged this task as Medium priority.Mar 25 2026, 11:07 PM
Atieno moved this task from Incoming (Needs Triage) to Backlog on the MW-Interfaces-Team board.

We should probably also discourage POST requests to action=query. POST should be reserved for actions the modify state. Using POST for query makes it impossible to see patterns in logs and metrics.

Change #1267086 had a related patch set uploaded (by Jforrester; author: Jforrester):

[mediawiki/core@master] [WIP] mediawiki.api: Always add the action parameter if available to the POSTed URL for traceability

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

Not doing so should trigger a warning in the response.

I'm not convinced about this. For some clients this will surely result in a warning on every single API query, which may hide more important warnings. I'd rather keep the warnings limited to stuff like deprecations.

The Action APIs documentation should state that the action parameter should be supplied as a query parameter, even for POST requests.

I think this should go into a new section on the main api.php documentation page, before "Data types", since there is quite a bit to explain even if we try to be brief.

First draft, thoughts welcome:

Request methods

Action API modules can accept GET and POST requests. Prefer using the GET method, unless the length of the URL with parameters would exceed its length limit (commonly 8 kB), or a module requires the POST method.

Parameters for POST requests may be set in the query part of the request URL (like in GET requests) and in the POST request body, and mixing both ways in one request is allowed. Certain sensitive parameters (documented individually) must be sent in the request body, while certain other parameters (in particular, the 'action' parameter, and others documented individually) should be sent in the request URL. Parameters must not be set to different values in the URL and body.

We should probably also discourage POST requests to action=query. POST should be reserved for actions the modify state. Using POST for query makes it impossible to see patterns in logs and metrics.

Note that api.log includes all parameters as processed by MediaWiki, both from the GET path and the POST body.

krinkle@mwlog1003:/srv/mw-log$ fgrep POST api.log | fgrep mw-api-ext | fgrep Krinkle | head

2026-04-03 01:20:14 […] mw-api-ext.eqiad.main-… commonswiki 1.46.0-wmf.22 api INFO: API POST KrinkleBot … T=1ms action=query format=json assertuser=KrinkleBot errorformat=plaintext meta=tokens formatversion=2  

2026-04-03 01:20:14 […] mw-api-ext.eqiad.main-… commonswiki 1.46.0-wmf.22 api INFO: API POST KrinkleBot 172.16.6.69 T=1279ms action=edit format=json assertuser=KrinkleBot errorformat=plaintext title=Project:Auto-protected%20files/wiktionary/en text=… summary=Update%20%5B%5BCommons:Auto-protected%20files%7Cauto-protection%5D%5D minor=1 token=[redacted] formatversion=2

The request is made by FileProtectionSyncBot.php which submits all parameters in the post body.

Not doing so should trigger a warning in the response.

I'm not convinced about this. For some clients this will surely result in a warning on every single API query, which may hide more important warnings. I'd rather keep the warnings limited to stuff like deprecations.

In talking to Daniel yesterday I understood this to essentially be a deprecation.

Not doing so should trigger a warning in the response.

I'm not convinced about this. For some clients this will surely result in a warning on every single API query, which may hide more important warnings. I'd rather keep the warnings limited to stuff like deprecations.

Yea... we should communicate it somehow, but we can discuss the mechanism and timeline.

Action API modules can accept GET and POST requests. Prefer using the GET method, unless the length of the URL with parameters would exceed its length limit (commonly 8 kB), or a module requires the POST method.

I'm wondering if we could restrict this to users with highlimits rights. The typical use case is listing a large number of titles or IPs to process in a query, which is generally very expensive.

Perhaps I should make a separate ticket for the "using POST for queries" aspect.

Parameters for POST requests may be set in the query part of the request URL (like in GET requests) and in the POST request body, and mixing both ways in one request is allowed. Certain sensitive parameters (documented individually) must be sent in the request body, while certain other parameters (in particular, the 'action' parameter, and others documented individually) should be sent in the request URL. Parameters must not be set to different values in the URL and body.

Sounds good! The only thing I'd change is in the last sentence: If the same parameter is sent as part of the URL and also in the request body, it must have the same value in both places.

Note that api.log includes all parameters as processed by MediaWiki, both from the GET path and the POST body.

Nice, that is good to know!

I still think that it would be very useful to have at least the action parameter visible e.g. in the error log on logstash or in the webrequest data set in turnilo.

In talking to Daniel yesterday I understood this to essentially be a deprecation.

At some point I think it should be. But it will probably take a long time, I don't know how soon we can even make it a serious warning.

For now it would already be a major improvement if we could make it a recommendation, and follow that recommendation in our own code.

Action API modules can accept GET and POST requests. Prefer using the GET method, unless the length of the URL with parameters would exceed its length limit (commonly 8 kB), or a module requires the POST method.

I'm wondering if we could restrict this to users with highlimits rights. The typical use case is listing a large number of titles or IPs to process in a query, which is generally very expensive.

50 titles is not generally very expensive, and you can hit those limits with fewer than that.

Btw I learned that "8000 bytes" is more correct than "8 kB" here. https://stackoverflow.com/a/417184

Perhaps I should make a separate ticket for the "using POST for queries" aspect.

Parameters for POST requests may be set in the query part of the request URL (like in GET requests) and in the POST request body, and mixing both ways in one request is allowed. Certain sensitive parameters (documented individually) must be sent in the request body, while certain other parameters (in particular, the 'action' parameter, and others documented individually) should be sent in the request URL. Parameters must not be set to different values in the URL and body.

Sounds good! The only thing I'd change is in the last sentence: If the same parameter is sent as part of the URL and also in the request body, it must have the same value in both places.

Done

Change #1269471 had a related patch set uploaded (by Bartosz Dziewoński; author: Bartosz Dziewoński):

[mediawiki/core@master] Action API landing page improvements

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

This patch adds a mention in the docs on the API landing page, as a soft recommendation:

(…) certain other parameters (in particular, the action parameter, and others documented individually) should be sent in the request URL

What about also encouraging people to pass query submodule parameters (prop=, list= and meta=) in the query string? While this cannot be made generally mandatory (since one can specify multiple submodules at once, it’s not impossible to get over the 8000-byte limit if sufficiently many extensions are installed on the wiki), it can still be useful in cases where it’s under the limit, which is probably the vast majority. It could also be made mandatory in special cases like T419130.

What about also encouraging people to pass query submodule parameters (prop=, list= and meta=) in the query string?

Yes, we could do that, though I'd prefer to go one step further: T422241: Action API: avoid using POST with action=query

Using POST with a query just doesn't make sense semantically. Though it may be needed for pragmatic reasons right now, we should work on solutions that avoid it.

I saw that, but due to the URL length limit discussed over there, I don’t think it’s realistic to expect people to (voluntarily) always use GET. And rather than (or in addition to) saying “include as many parameters as possible”, I think it’s more important to say which parameters have higher priority – maybe one can use more of the 8000-byte limit if one puts shorter parameters in the URL (say, rvdir=newer&rvtag=foo rather than prop=revisions|categories), yet it’s more useful information to know that they requested revisions and categories (the latter cannot even be deduced from the short parameters I used in my example) than the specifics of the revisions request.

yet it’s more useful information to know that they requested revisions and categories (the latter cannot even be deduced from the short parameters I used in my example) than the specifics of the revisions request.

Yea, I agree. We can add it to the etiquette.

Change #1267086 merged by jenkins-bot:

[mediawiki/core@master] mediawiki.api: Always add the action parameter if available to the POSTed URL for traceability

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

Change #1271984 had a related patch set uploaded (by Jforrester; author: Jforrester):

[mediawiki/extensions/UploadWizard@master] mw.FormDataTransport.test: Update expected API call for POSTed calls

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

Change #1271984 merged by jenkins-bot:

[mediawiki/extensions/UploadWizard@master] mw.FormDataTransport.test: Update expected API call for POSTed calls

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

Sigh. More stupid ideas to break tons of existing clients because of the poorly thought through rate limiting garbage.

To be clear, I am for making this a recommendation, but I am against making it a warning, a deprecation, an error, or a breaking change. I don't think any timeline would be appropriate for that. There is no reason to break clients on WMF wikis that don't exceed the new rate limits, or any clients on other wikis.

I think having the parameter in the URL is genuinely useful. On WMF wikis it's only needed if you want your client to be exempt from rate limits for specific actions, like logging in (and while we have other logs for the API actions taken, due to the way the params are passed, we can't determine the action until the processing of the request is way past the point where we'd like to reject it). On any wiki, it is useful to have when working with browser developer tools, and it is useful for more low-tech logging solutions like Apache access logs.

@Anomie I noticed you didn't comment on T421287, so I take it you at least agree with that change. And I'd really appreciate your review of the landing page changes, although I don't mind if you don't want to volunteer for that.

Something to keep in mind is that one of the guiding principles of the Action API (at least from around 2012 until 2020) is that it uses HTTP as a transport but remains agnostic about the details whenever possible. Requiring certain parameters to be in the POST body or the query string has been limited to transport-level concerns like security for the former and CORS operation for the latter. This is also why the Action API doesn't use generally HTTP status codes to represent errors outside of transport-level issues and certain endpoints like ApiCSPReport where a protocol requires it.

Any changes to that should consider whether the disruption to the many users of the API is worth the claimed benefit. The changes called for here and in T422241 come nowhere near meeting that requirement, and in particular the whole "rate limiting" project seems to be poorly conceived from the start.

As for T421287, I think it would be valid to detect when $_GET and $_POST contain the same parameter with different values and raise an error about that situation. The approach suggested in the task description is not a good one, however. T421287#11804480 is better, but IMO ApiEntryPoint (where it checks for pathinfo) or ApiMain::setupExternalResponse() (where it checks for unsupported HTTP methods) seem like better places. And like those, since this actually is a transport-level issue, a 400 response would be appropriate IMO. Or maybe the check could even go in general MediaWiki setup code, where it can protect the web UI as well.

Also, regarding T410883, much the same applies: allowing QUERY would be fine, but unless some protocol requires it or there are transport-related reasons, the API shouldn't care whether QUERY or POST or GET was used.

P.S. I'm not terribly fond of the "Request methods" language you're adding in https://gerrit.wikimedia.org/r/c/mediawiki/core/+/1269471. Quite a bit of it seems WMF-specific, but you're putting it into messages that will be used by all MediaWiki installations, and you're leaving things vague because you don't even know what "WMF" might actually want to try to require in the future. IMO, if it's going to discuss request methods at all, it should be talking about how to determine which modules require POST (i.e. the ones with "api-help-flag-mustbeposted") and which can't be used with QUERY (i.e. presumably "api-help-flag-writerights"). If you're going to push GET/QUERY at all, give actual reasons why they are better. If WMF really is going to try to read certain parameters from the query string for some reason, use a WMF-specific message to specifically document which ones, why, and what the actual consequences are for having them in the POST/QUERY body, instead of the vague hand-waving about "try to cram as much as you can in the query string".

And be prepared for many existing clients to keep doing what they're already doing. Unless you make things actually break, and then be prepared for many complaints because existing clients are mostly maintained by volunteers without a whole lot of free time to chase arbitrary changes.

Something to keep in mind is that one of the guiding principles of the Action API (at least from around 2012 until 2020) is that it uses HTTP as a transport but remains agnostic about the details whenever possible.

Is that written down somewhere?

Requiring certain parameters to be in the POST body or the query string has been limited to transport-level concerns like security for the former and CORS operation for the latter.

That's exactly what motivates this ticket, and also T422241: POST requests have to be routed to the primary DC, and the action is needed to decide on rate limiting. Both are transport layer concerns.

I'm not suggesting we should reject requests that don't put the action into the query string. But we should somehow inform the client that they are missing out on optimization that would benefit both us and them. Whether a "warning" is the best mechanism for that I don't know. What would you use?

This is also why the Action API doesn't use generally HTTP status codes to represent errors outside of transport-level issues and certain endpoints like ApiCSPReport where a protocol requires it.

I thought that was primarily to ensure support for JSON-P. It's a constant point of confusion with clients, and makes it harder to gather good metrics on errors.

Is that written down somewhere?

Various tasks and mailing list discussions over the years, I'm sure. An early one is T40716#461184, which was reiterated a few times in https://www.mediawiki.org/wiki/Talk:Requests_for_comment/API_roadmap.

I don't recall whether it made it onto non-talk wiki pages somewhere. Then again, even stuff clearly written on wikipages is being ignored, so it's not like that makes much of a difference.

That's exactly what motivates this ticket, and also T422241: POST requests have to be routed to the primary DC, and the action is needed to decide on rate limiting. Both are transport layer concerns.

I was referring to concerns like "CORS requires sending an OPTIONS request" or "proxies may log query strings, and leak those logs, so let's require passwords be in a POST body". Requirements from external standards, or systems on the Internet at large.

What motivates this ticket is that you're wanting to make up new "transport-layer" concerns to make some ideas you've had easier.

I'm not suggesting we should reject requests that don't put the action into the query string.

T421288#11785213 indicates otherwise.

But we should somehow inform the client that they are missing out on optimization that would benefit both us and them. Whether a "warning" is the best mechanism for that I don't know. What would you use?

Warnings are for cases where an incomplete response can still be returned (versus just an error message) or for where something will break in the future (e.g. deprecations). "Your request might be processed slightly more slowly in WMF's infrastructure" isn't either of those.

I thought that was primarily to ensure support for JSON-P.

Then you thought wrong. There seems to be a lot of that going around lately.

It's a constant point of confusion with clients,

I doubt that, or T40716: API should use status codes for errors would have a lot more duplicates and people wanting to re-open it.

Maybe people who're newly looking and haven't figured out that the Action API isn't a REST API, but likely they figure that out pretty quickly. Or they go use the actual REST API.

Meanwhile, it means clients don't have to try parsing responses with non-200 response codes to see whether it's a formatted API error or HTML from some transport-layer error.

and makes it harder to gather good metrics on errors.

I doubt that too. I see a bunch of stats calls in ApiMain::handleException() that will be giving much more granular metrics than you'd be able to get from logging HTTP status codes.

P.S. I'm not terribly fond of the "Request methods" language you're adding in https://gerrit.wikimedia.org/r/c/mediawiki/core/+/1269471. Quite a bit of it seems WMF-specific, but you're putting it into messages that will be used by all MediaWiki installations, and you're leaving things vague because you don't even know what "WMF" might actually want to try to require in the future.

I'm not terribly fond of it myself, and it's true that it's vague because it's trying to say what WMF wants without being WMF-specific. Still, I think that everything I put there is good advice for all MediaWiki installations, and following it would make the lives of operators of both API clients and servers a tiny bit easier.

IMO, if it's going to discuss request methods at all, it should be talking about how to determine which modules require POST (i.e. the ones with "api-help-flag-mustbeposted") and which can't be used with QUERY (i.e. presumably "api-help-flag-writerights").

It already says the first thing ("Prefer using the GET method, unless … a module requires the POST method"). I tweaked this wording to match the one used for flags in API documentation.

I'm not sure what you mean with the second thing. Are you saying that "writerights" modules should use POST method? It seems that in theory they can be used with GET right now, and so presumably QUERY will also be okay (but it seems all of them also have the "mustbeposted" flag).

If you're going to push GET/QUERY at all, give actual reasons why they are better.

Good idea, I added half a sentence. (I'm trying to keep this short.)

If WMF really is going to try to read certain parameters from the query string for some reason, use a WMF-specific message to specifically document which ones, why, and what the actual consequences are for having them in the POST/QUERY body, instead of the vague hand-waving about "try to cram as much as you can in the query string".

The patch I proposed does not suggest cramming as much as you can in the query string. I'm not sure how to make it clearer. I rephrased things to document the whys better.

Btw I realized we don't have a way to mark which parameters must be in POST body in the generated documentation. You can only learn to do this right from an error message if you do it wrong. We can only mark "sensitive" parameters, which is not the same thing (see 4d38a489). I reworded the part that applies to this.

Change #1276012 had a related patch set uploaded (by MusikAnimal; author: Jforrester):

[mediawiki/extensions/UploadWizard@wmf/1.46.0-wmf.24] mw.FormDataTransport.test: Update expected API call for POSTed calls

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

Change #1276012 merged by jenkins-bot:

[mediawiki/extensions/UploadWizard@wmf/1.46.0-wmf.24] mw.FormDataTransport.test: Update expected API call for POSTed calls

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

Mentioned in SAL (#wikimedia-operations) [2026-04-21T20:51:09Z] <musikanimal@deploy1003> Started scap sync-world: Backport for [[gerrit:1276012|mw.FormDataTransport.test: Update expected API call for POSTed calls (T423529 T421288)]]

Mentioned in SAL (#wikimedia-operations) [2026-04-21T20:52:45Z] <musikanimal@deploy1003> musikanimal: Backport for [[gerrit:1276012|mw.FormDataTransport.test: Update expected API call for POSTed calls (T423529 T421288)]] synced to the testservers (see https://wikitech.wikimedia.org/wiki/Mwdebug). Changes can now be verified there.

Mentioned in SAL (#wikimedia-operations) [2026-04-21T20:57:36Z] <musikanimal@deploy1003> Finished scap sync-world: Backport for [[gerrit:1276012|mw.FormDataTransport.test: Update expected API call for POSTed calls (T423529 T421288)]] (duration: 06m 27s)

I'm not terribly fond of it myself, and it's true that it's vague because it's trying to say what WMF wants without being WMF-specific. Still, I think that everything I put there is good advice for all MediaWiki installations, and following it would make the lives of operators of both API clients and servers a tiny bit easier.

If it would make the lives of API clients easier, I wouldn't be pushing back on it.

I'm not sure what you mean with the second thing. Are you saying that "writerights" modules should use POST method? It seems that in theory they can be used with GET right now, and so presumably QUERY will also be okay (but it seems all of them also have the "mustbeposted" flag).

What I'm saying is that, if QUERY is limited in the same way as GET with Promise-Non-Write-API-Action is, as T410883 calls for, it won't be able to be used for any module lacking "writerights".

OTOH, it seems like QUERY might also be ok for a "mustbeposted", since at quick glance it seems it also has stuff in the body part.

The patch I proposed does not suggest cramming as much as you can in the query string.

True, that's more what T422241 is calling for. OTOH, "use GET unless your data is more than 8000 bytes" is still moving in that direction.

I'm not terribly fond of it myself, and it's true that it's vague because it's trying to say what WMF wants without being WMF-specific. Still, I think that everything I put there is good advice for all MediaWiki installations, and following it would make the lives of operators of both API clients and servers a tiny bit easier.

If it would make the lives of API clients easier, I wouldn't be pushing back on it.

Well… adding it to the JS mw.Api made my life easier the other day when I was debugging a CORS issue and I could distinguish the different OPTIONS requests at a glance in my browser's dev tools. Your mileage may vary.

I'm not sure what you mean with the second thing. Are you saying that "writerights" modules should use POST method? It seems that in theory they can be used with GET right now, and so presumably QUERY will also be okay (but it seems all of them also have the "mustbeposted" flag).

What I'm saying is that, if QUERY is limited in the same way as GET with Promise-Non-Write-API-Action is, as T410883 calls for, it won't be able to be used for any module lacking "writerights".

OTOH, it seems like QUERY might also be ok for a "mustbeposted", since at quick glance it seems it also has stuff in the body part.

Thanks, this makes sense. Since we don't allow QUERY now, there's no place for this in the current patch, but I added a note in T410883#11857487.

Change #1269471 merged by jenkins-bot:

[mediawiki/core@master] Action API landing page improvements

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

matmarex updated the task description. (Show Details)