From 942e8b36e4eafa550c6f699cbffcc37dce380a63 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Fri, 4 Dec 2020 10:38:14 -0700 Subject: [PATCH] Convert to markdown verbatim --- proposals/1337-improve-membership.md | 155 +++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 proposals/1337-improve-membership.md diff --git a/proposals/1337-improve-membership.md b/proposals/1337-improve-membership.md new file mode 100644 index 00000000..52047feb --- /dev/null +++ b/proposals/1337-improve-membership.md @@ -0,0 +1,155 @@ +# Improving the way membership lists are queried + +## Problem scope + +A common operation for bots, bridges, scripts, and clients is to determine what rooms the user is a +member of and who the members of those rooms are. Although possible with the current specification, +the API can be improved to provide more granular and simplified access to this information. + +The affected routes are: + +* `GET /_matrix/client/r0/rooms/{roomId}/members` +* `GET /_matrix/client/r0/rooms/{roomId}/joined_members` +* `GET /_matrix/client/r0/joined_rooms` + +This proposal aims to resolve [matrix-doc#1123](https://github.com/matrix-org/matrix-doc/issues/1123). + +## Background + +The `/joined_members` and `/joined_rooms` endpoints were originally added in [synapse#1680](https://github.com/matrix-org/synapse/pull/1680) +during a time when the IRC bridge on matrix.org was under extreme load. The endpoints were fully +intended to alleviate load by having the bridge do less work and have the server doing more. + +## Proposal + +This proposal calls for both `/joined_members` and `/joined_rooms` to be deprecated. The +deprecation is to be coupled with improving how `/members` works and introducing a new `/rooms` +endpoint, which will work in a very similar way to the updated `/members` endpoint. Both endpoints +are proposed to get some way to filter based upon membership, as outlined in the options below. + +### Option 1: Query string + +A new query parameter, `membership`, should be added to the `/members` endpoint. The parameter +filters the membership list of the room such that only members with a matching `membership` are +returned. The parameter can be supplied multiple times to filter on multiple membership states. For +example, the request could be `/members?membership=join&membership=invite` to get all invited and +joined members for the room. If no `membership` parameter is specified, the default is to return +all members of the room regardless of membership state. + +To compliment the `/members` endpoint, a new endpoint should be added to query the rooms for the +user. This uses the same style of using a membership query parameter to filter the rooms. + +Some examples of using this endpoint are below. The `rooms` field is an object where the key is a +room ID and the value is information about that room, currently storing a single `membership` +field. The value is an object to support future expansion of this API. + +```json5 +// GET /_matrix/client/r0/rooms?membership=join&membership=invite +{ + "rooms": { + "!somewhere:domain.com": { + "membership": "join" + }, + "!elsewhere:matrix.org": { + "membership": "invite" + } + } +} +``` + +```json5 +// GET /_matrix/client/r0/rooms?membership=ban +{ + "rooms": { + "!plzno:domain.com": { + "membership": "ban" + } + } +} +``` + +```json5 +// GET /_matrix/client/r0/rooms +{ + "rooms": { + "!somewhere:domain.com": { + "membership": "join" + }, + "!elsewhere:matrix.org": { + "membership": "invite" + }, + "!plzno:domain.com": { + "membership": "ban" + }, + "!curbaf:domain.com": { + "membership": "leave" + } + } +} +``` + +### Option 2: Filter + +As with Option 1, a new endpoint would be added to handle getting the list of rooms. However, instead of both `/members` and `/rooms` taking a query parameter for membership they would instead take a filter (re-using existing matrix concepts). Similar to how `/messages` works, this filter would be a `RoomEventFilter` instead of having all the available options. Additionally, the filter would support a `membership` field to filter based upon membership. + +An example filter for getting members/rooms of membership `invite` or `join` would be: + +```json5 +{ + "limit": 5, // The maximum number of items to return. Defaults to no limit. + + // These only apply when fetching members in a room + "senders": ["*"], + "not_senders": [], + + // These only apply when fetching rooms + "rooms": ["*"], + "not_rooms": [], + + // NEW! Filter based upon the given membership values. + "membership": ["join", "invite"], + + // These are copied from the RoomEventFilter schema, but are ignored + "types": [], + "not_types": [], + "contains_url": true, +} +``` + +### Option 3: Even more filters + +Expanding on Option 2, we give `/state` the option of a filter (also from Option 2). This would +require the `types` to be useful, and we could potentially deprecate the `/members` endpoint +entirely with this approach. + +Likewise, `/context` should take a similar filter so clients can get members at a given point in +history. + +## Alternative solutions + +### Using ?membership=join,invite or ?membership=join+invite instead + +The arguments in favour of this approach are: + +* It doesn’t rely on undefined behaviour in RFC3986 +* Using multiple keys in the query string hasn’t been done before in the matrix spec + +The arguments against this approach are: + +* It’s not as pretty and may require hex encoding +* It adds unnecessary complexity given most query string parsers are capable of handling multiple + keys in the query string. It is additional complexity because implementations would now need to + do string splitting instead of relying on their already-in-use parsing libraries + +### Encoding ?membership as a JSON value + +The arguments in favour of this approach are: + +* The filtering API already does this +* It doesn’t rely on undefined behaviour in RFC3986 + +The arguments against this approach are: + +* It’s not as pretty and requires hex encoding +* Implementations would be forced to perform decoding, adding additional complexity (see the con + for comma-separated values)