matrix-doc/proposals/2356-bulk-joined-members.md

106 lines
4.2 KiB
Markdown

# MSC2356 - Bulk /joined_members endpoint
[`/rooms/{roomId}/joined_members`](https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-client-r0-rooms-roomid-joined-members)
is an endpoint designed for bots and bridges that want to get the list of members
in a room, and their profile information. Because it does not try to return the full event format,
an equivalent call in [`/rooms/{roomId}/members`](https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-client-r0-rooms-roomid-members)
will take longer to complete.
However, bridges often need to get membership information about rooms on startup to do things like
connect Matrix users to a IRC connection or sync membership across. The matrix.org hosted Freenode
IRC bridge made 15315 requests to `/joined_members` when it was last restarted, which took 17 minutes
to complete. Because of this delay, the bridge was unusable for that time period while it was still
connecting membership information.
Clearly, there should be a better way to pull membership for many rooms which doesn't involve making
many calls to the homeserver.
## Proposal
This proposal covers the creation of a bulk room membership endpoint.
The new endpoint will be called `POST /_matrix/client/r0/joined_members` and will not
take a `room_id` parameter. Rather a JSON body should be posted containing the list of rooms the
user is interested in. A JSON body is used rather than a query parameter because as in the example
above, the number of rooms may spill into the 10000s range which may cause issues with URI parsers,
or any intemedary load balancers.
[RFC7230 states](https://tools.ietf.org/html/rfc7230#section-3.1.1) that the minimum recommended
length of a URL is 8000 octets, but this means that we cannot rely on support beyond that number.
#### Example request body
```
{
"rooms": [
"!foo:bar",
"!bar:baz",
"!not:real",
]
}
```
The `rooms` array SHOULD be checked for duplicates and only one response should
be returned for each unique `room_id`.
#### Example response body
```
{
"joined": {
"!foo:bar": {
"@bar:example.com": {
"display_name": "Bar",
"avatar_url": "mxc://riot.ovh/printErCATzZijQsSDWorRaK"
}
}
"!bar:baz" :{
"@foo:example.com": {
"display_name": "Foo",
"avatar_url": "mxc://riot.ovh/printErCATzZijQsSDWorRaK"
},
"@bar:example.com": {
"display_name": "Bar",
"avatar_url": "mxc://riot.ovh/printErCATzZijQsSDWorRaK"
}
}
"!not:real": null,
}
}
```
`joined["room_id"]` follows the same format as `joined` in `/rooms/{roomId}/joined_members`.
Any rooms where membership could not be fetched MUST be returned as null.
The reason for not throwing an error is that applications may not want to lose the
rest of the data because a room was not available to them. Applications SHOULD infer
that a `null` value means the authenticated user does not have permission to view the
membership of that room. They should retry with a different request if they want to
know the reason.
## Potential issues
If an implementation is done poorly, it's possible to use this request to wedge
a homeserver by requesting membership from a huge number of rooms. Homeservers COULD
limit the number of rooms that can be requested, and return an error if that number is
exceeded. In this case, it is recommended that the homeserver raise limits for
application services independently of normal users.
The response size of this request may be rather large, so implementors should take care to
allow for large payloads.
The time taken to serve this request may exceed the timeout of the request, so similiar semantics
COULD be applied as they are in /sync where the request continues to run on the homeserver
and is resumed when the next call to the endpoint is made.
## Alternatives
The current alternative solution to this problem is to keep running many `/joined_members`
requests concurrently to achieve the same result. As explained in the
introduction, this is not ideal.
## Security considerations
None. The endpoint should follow the same authorisation checks that the `/joined_members` endpoint makes.