Merge pull request #108 from matrix-org/appservice-swagger

Swaggerify application services
pull/120/merge
Kegsay 9 years ago
commit 73142fe76e

@ -0,0 +1,201 @@
swagger: '2.0'
info:
title: "Matrix Application Service API"
version: "1.0.0"
host: localhost:8008
schemes:
- https
- http
basePath: "/"
consumes:
- application/json
produces:
- application/json
paths:
"/transactions/{txnId}":
put:
summary: Send some events to the application service.
description: |-
This API is called by the HS when the HS wants to push an event (or
batch of events) to the AS.
parameters:
- in: path
name: txnId
type: string
description: |-
The transaction ID for this set of events. Homeservers generate
these IDs and they are used to ensure idempotency of requests.
required: true
x-example: "35"
- in: body
name: body
description: A list of events
schema:
type: object
example: |-
{
"events": [
{
"age": 32,
"content": {
"body": "incoming message",
"msgtype": "m.text"
},
"event_id": "$14328055551tzaee:localhost",
"origin_server_ts": 1432804485886,
"room_id": "!TmaZBKYIFrIPVGoUYp:localhost",
"type": "m.room.message",
"user_id": "@bob:localhost"
},
{
"age": 1984,
"content": {
"body": "another incoming message",
"msgtype": "m.text"
},
"event_id": "$1228055551ffsef:localhost",
"origin_server_ts": 1432804485886,
"room_id": "!TmaZBKYIFrIPVGoUYp:localhost",
"type": "m.room.message",
"user_id": "@bob:localhost"
}
]
}
description: "Transaction informations"
properties:
events:
type: array
description: A list of events
items:
type: object
title: Event
required: ["events"]
responses:
200:
description: The transaction was processed successfully.
examples:
application/json: |-
{}
schema:
type: object
"/rooms/{roomAlias}":
get:
summary: Query if a room alias should exist on the application service.
description: |-
This endpoint is invoked by the homeserver on an application service to query
the existence of a given room alias. The homeserver will only query room
aliases inside the application service's ``aliases`` namespace. The
homeserver will send this request when it receives a request to join a
room alias within the application service's namespace.
parameters:
- in: path
name: roomAlias
type: string
description: The room alias being queried.
required: true
x-example: "#magicforest:example.com"
responses:
200:
description: |-
The application service indicates that this room alias exists. The
application service MUST have created a room and associated it with
the queried room alias using the client-server API. Additional
information about the room such as its name and topic can be set
before responding.
examples:
application/json: |-
{}
schema:
type: object
401:
description: |-
The homeserver has not supplied credentials to the application service.
Optional error information can be included in the body of this response.
examples:
application/json: |-
{
"errcode": "COM.EXAMPLE.MYAPPSERVICE_UNAUTHORIZED"
}
schema:
type: object
403:
description: |-
The credentials supplied by the homeserver were rejected.
examples:
application/json: |-
{
"errcode": "M_FORBIDDEN"
}
schema:
type: object
404:
description: |-
The application service indicates that this room alias does not exist.
Optional error information can be included in the body of this response.
examples:
application/json: |-
{
"errcode": "COM.EXAMPLE.MYAPPSERVICE_NOT_FOUND"
}
schema:
type: object
"/users/{userId}":
get:
summary: Query if a user should exist on the application service.
description: |-
This endpoint is invoked by the homeserver on an application service to query
the existence of a given user ID. The homeserver will only query user IDs
inside the application service's ``users`` namespace. The homeserver will
send this request when it receives an event for an unknown user ID in
the application service's namespace.
parameters:
- in: path
name: userId
type: string
description: The user ID being queried.
required: true
x-example: "@alice:example.com"
responses:
200:
description: |-
The application service indicates that this user exists. The application
service MUST create the user using the client-server API.
examples:
application/json: |-
{}
schema:
type: object
401:
description: |-
The homeserver has not supplied credentials to the application service.
Optional error information can be included in the body of this response.
examples:
application/json: |-
{
"errcode": "COM.EXAMPLE.MYAPPSERVICE_UNAUTHORIZED"
}
schema:
type: object
403:
description: |-
The credentials supplied by the homeserver were rejected.
examples:
application/json: |-
{
"errcode": "M_FORBIDDEN"
}
schema:
type: object
404:
description: |-
The application service indicates that this user does not exist.
Optional error information can be included in the body of this response.
examples:
application/json: |-
{
"errcode": "COM.EXAMPLE.MYAPPSERVICE_NOT_FOUND"
}
schema:
type: object

@ -4,7 +4,7 @@ Application Service API
The Matrix client-server API and server-server APIs provide the means to
implement a consistent self-contained federated messaging fabric. However, they
provide limited means of implementing custom server-side behaviour in Matrix
(e.g. gateways, filters, extensible hooks etc). The Application Service API
(e.g. gateways, filters, extensible hooks etc). The Application Service API (AS API)
defines a standard API to allow such extensible functionality to be implemented
irrespective of the underlying homeserver implementation.
@ -12,15 +12,18 @@ irrespective of the underlying homeserver implementation.
Add in Client-Server services? Overview of bots? Seems weird to be in the spec
given it is VERY implementation specific.
Passive Application Services
----------------------------
"Passive" application services can only observe events from a given home server,
and inject events into a room they are participating in.
Application Services
--------------------
Application services are passive and can only observe events from a given
homeserver. They can inject events into rooms they are participating in.
They cannot prevent events from being sent, nor can they modify the content of
the event being sent. In order to observe events from a homeserver, the
homeserver needs to be configured to pass certain types of traffic to the
application service. This is achieved by manually configuring the homeserver
with information about the AS.
with information about the application service (AS).
Registration
~~~~~~~~~~~~
.. NOTE::
Previously, application services could register with a homeserver via HTTP
@ -38,7 +41,30 @@ with information about the AS.
A better solution would be to somehow mandate that the API done to avoid
abuse.
An example HS configuration required to pass traffic to the AS is:
Application services register "namespaces" of user IDs, room aliases and room IDs.
These namespaces are represented as regular expressions. An application service
is said to be "interested" in a given event if one of the IDs in the event match
the regular expression provided by the application service. An application
service can also state whether they should be the only ones who
can manage a specified namespace. This is referred to as an "exclusive"
namespace. An exclusive namespace prevents humans and other application
services from creating/deleting entities in that namespace. Typically,
exclusive namespaces are used when the rooms represent real rooms on
another service (e.g. IRC). Non-exclusive namespaces are used when the
application service is merely augmenting the room itself (e.g. providing
logging or searching facilities). Namespaces are represented by POSIX extended
regular expressions and look like:
.. code-block:: yaml
users:
- exclusive: true
regex: @irc.freenode.net_.*
The registration is represented by a series of key-value pairs, which this
specification will present as YAML. An example HS configuration required to pass
traffic to the AS is:
.. code-block:: yaml
@ -59,135 +85,15 @@ An example HS configuration required to pass traffic to the AS is:
``as_token`` MUST be unique per application service as this token is used to
identify the application service. The homeserver MUST enforce this.
- An application service can state whether they should be the only ones who
can manage a specified namespace. This is referred to as an "exclusive"
namespace. An exclusive namespace prevents humans and other application
services from creating/deleting entities in that namespace. Typically,
exclusive namespaces are used when the rooms represent real rooms on
another service (e.g. IRC). Non-exclusive namespaces are used when the
application service is merely augmenting the room itself (e.g. providing
logging or searching facilities).
- Namespaces are represented by POSIX extended regular expressions,
e.g:
.. code-block:: yaml
users:
- exclusive: true
regex: @irc.freenode.net_.*
Home Server -> Application Service API
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This contains application service APIs which are used by the home server. All
application services MUST implement these APIs.
User Query
++++++++++
This API is called by the HS to query the existence of a user on the Application
Service's namespace.
Inputs:
- User ID
- HS Credentials
Output:
- Whether the user exists.
Side effects:
- User is created on the HS by the AS via CS APIs during the processing of this request.
API called when:
- HS receives an event for an unknown user ID in the AS's namespace, e.g. an
invite event to a room.
Notes:
- When the AS receives this request, if the user exists, it must `create the user`_ via
the CS API.
- It can also set arbitrary information about the user (e.g. display name, join rooms, etc)
using the CS API.
- When this setup is complete, the AS should respond to the HS request. This means the AS
blocks the HS until the user is created.
- This is deemed more flexible than alternative methods (e.g. returning a JSON blob with the
user's display name and get the HS to provision the user).
Retry notes:
- The home server cannot respond to the client's request until the response to
this API is obtained from the AS.
- Recommended that home servers try a few times then time out, returning a
408 Request Timeout to the client.
::
GET /users/$user_id?access_token=$hs_token
Pushing events
++++++++++++++
Returns:
200 : User is recognised.
404 : User not found.
401 : Credentials need to be supplied.
403 : HS credentials rejected.
200 OK response format
{}
Room Alias Query
++++++++++++++++
This API is called by the HS to query the existence of a room alias on the
Application Service's namespace.
Inputs:
- Room alias
- HS Credentials
Output:
- Whether the room exists.
Side effects:
- Room is created on the HS by the AS via CS APIs during the processing of
this request.
API called when:
- HS receives an event to join a room alias in the AS's namespace.
Notes:
- When the AS receives this request, if the room exists, it must create the room via
the CS API.
- It can also set arbitrary information about the room (e.g. name, topic, etc)
using the CS API.
- It can send messages as other users in order to populate scrollback.
- When this setup is complete, the AS should respond to the HS request. This means the AS
blocks the HS until the room is created and configured.
- This is deemed more flexible than alternative methods (e.g. returning an initial sync
style JSON blob and get the HS to provision the room). It also means that the AS knows
the room ID -> alias mapping.
Retry notes:
- The home server cannot respond to the client's request until the response to
this API is obtained from the AS.
- Recommended that home servers try a few times then time out, returning a
408 Request Timeout to the client.
::
GET /rooms/$room_alias?access_token=$hs_token
Returns:
200 : Room is recognised.
404 : Room not found.
401 : Credentials need to be supplied.
403 : HS credentials rejected.
200 OK response format
{}
Pushing
+++++++
This API is called by the HS when the HS wants to push an event (or batch of
events) to the AS.
Inputs:
- HS Credentials
- Event(s) to give to the AS
- HS-generated transaction ID
Output:
- None.
Data flows:
The application service API provides a transaction API for sending a list of
events. Each list of events includes a transaction ID, which works as follows:
::
@ -201,35 +107,45 @@ Data flows:
HS ---> AS : Home server retries with the same transaction ID of T.
<--- : AS sends back 200 OK. If the AS had processed these events
already, it can NO-OP this request (and it knows if it is the same
events based on the transacton ID).
events based on the transaction ID).
The events sent to the application service should be linearised, as if they were
from the event stream. The homeserver MUST maintain a queue of transactions to
send to the AS. If the application service cannot be reached, the homeserver
SHOULD backoff exponentially until the application service is reachable again.
As application services cannot *modify* the events in any way, these requests can
be made without blocking other aspects of the homeserver. Homeservers MUST NOT
alter (e.g. add more) events they were going to send within that transaction ID
on retries, as the AS may have already processed the events.
Querying
++++++++
The application service API includes two querying APIs: for room aliases and for
user IDs. The application service SHOULD create the queried entity if it desires.
During this process, the application service is blocking the homeserver until the
entity is created and configured. If the homeserver does not receive a response
to this request, the homeserver should retry several times before timing out. This
should result in an HTTP status 408 "Request Timeout" on the client which initiated
this request (e.g. to join a room alias).
Retry notes:
- If the HS fails to pass on the events to the AS, it must retry the request.
- Since ASes by definition cannot alter the traffic being passed to it (unlike
say, a Policy Server), these requests can be done in parallel to general HS
processing; the HS doesn't need to block whilst doing this.
- Home servers should use exponential backoff as their retry algorithm.
- Home servers MUST NOT alter (e.g. add more) events they were going to
send within that transaction ID on retries, as the AS may have already
processed the events.
.. admonition:: Rationale
Ordering notes:
- The events sent to the AS should be linearised, as they are from the event
stream.
- The home server will need to maintain a queue of transactions to send to
the AS.
Blocking the homeserver and expecting the application service to create the entity
using the client-server API is simpler and more flexible than alternative methods
such as returning an initial sync style JSON blob and get the HS to provision
the room/user. This also meant that there didn't need to be a "backchannel" to inform
the application service about information about the entity such as room ID to
room alias mappings.
::
PUT /transactions/$transaction_id?access_token=$hs_token
HTTP APIs
+++++++++
Request format
{
events: [
...
]
}
This contains application service APIs which are used by the home server. All
application services MUST implement these APIs. These APIs are defined below.
{{application_service_http_api}}
.. _create the user: `sect:asapi-permissions`_
@ -237,7 +153,7 @@ Ordering notes:
Client-Server v2 API Extensions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Passive application services can utilise a more powerful version of the
Application services can utilise a more powerful version of the
client-server API by identifying itself as an application service to the
home server.

@ -153,7 +153,7 @@ class MatrixUnits(Units):
for path in api["paths"]:
for method in api["paths"][path]:
single_api = api["paths"][path][method]
full_path = api.get("basePath", "") + path
full_path = api.get("basePath", "").rstrip("/") + path
endpoint = {
"title": single_api.get("summary", ""),
"desc": single_api.get("description", single_api.get("summary", "")),
@ -299,7 +299,7 @@ class MatrixUnits(Units):
)
]
if len(params_missing_examples) == 0:
path_template = api.get("basePath", "") + path
path_template = api.get("basePath", "").rstrip("/") + path
qps = {}
body = ""
for param in single_api.get("parameters", []):
@ -398,7 +398,7 @@ class MatrixUnits(Units):
})
return {
"base": api.get("basePath"),
"base": api.get("basePath").rstrip("/"),
"group": group_name,
"endpoints": endpoints,
}

Loading…
Cancel
Save