summaryrefslogtreecommitdiff
path: root/docs/api/channels-messages.md
blob: 1eca1b45a0ec8f232b9cfacc9d36b274cbfe3bde (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
# Channels and messages

```mermaid
---
Channel lifecycle
---
stateDiagram-v2
	[*] --> Active : POST /api/channels
	Active --> Deleted : DELETE /api/channels/C1234
	Active --> Deleted : Expiry
	Deleted --> [*] : Purge
```

```mermaid
---
Message lifecycle
---
stateDiagram-v2
	[*] --> Sent : POST /api/channels/C1234
	Sent --> Deleted : DELETE /api/messages/Mabcd
	Sent --> Deleted : Expiry
	Deleted --> [*] : Purge
```

Messages allow logins to communicate with one another. Channels are the conversations to which those messages are sent.

Every channel has a unique name, chosen when the channel is created.

## Names

<!-- This prose is duplicated in authentication.md. If you change it here, consider changing it there, too. -->
The service handles channel names using two separate forms.

The first form is as given in the request used to create the channel. This form of the channel name is used throughout the API, and the service will preserve the name as entered (other than applying normalization), so that users' preferences around capitalization and accent marks are preserved.

The second form is a "canonical" form, used internally by the service to control uniqueness and match names to channels. The canonical form is both case-folded and normalized.

The canonical form is not available to API clients, but its use has practical consequences. Names that differ only by case or only by code point sequence are treated as the same name. If the name is in use, changing the capitalization or changing the sequence of combining marks will not allow the creation of a second "identical" channel.

## Expiry and purging

Both channels and messages expire after a time. Messages expire 90 days after being sent. Channels expire 90 days after the last message sent to them, or after creation if no messages are sent in that time.

Deleted channels and messages, including those that have expired, are temporarily retained by the service, to allow clients that are not connected to receive the corresponding deletion [events](./events.md). To limit storage growth, deleted channels and messages are purged from the service seven days after they were deleted.

## `POST /api/channels`

Creates a channel.

### Request

```json
{
  "name": "a unique channel name"
}
```

The request must have the following fields:

| Field  | Type   | Description         |
|:-------|:-------|:--------------------|
| `name` | string | The channel's name. |

The proposed `name` must be valid. The precise definition of valid is still up in the air, but, at minimum:

* It must be non-empty.
* It must not be "too long." (Currently, 64 characters is too long.)
* It must begin with a printing character.
* It must end with a printing character.
* It must not contain runs of multiple whitespace characters.

### Success

This endpoint will respond with a status of
`202 Accepted` when successful. The body of the response will be a JSON object describing the new channel:

```json
{
  "id": "C9876cyyz",
  "name": "a unique channel name"
}
```

The response will have the following fields:

| Field  | Type   | Description                                                                                                                             |
|:-------|:-------|:----------------------------------------------------------------------------------------------------------------------------------------|
| `id`   | string | A unique identifier for the channel. This can be used to associate the channel with events, or to make API calls targeting the channel. |
| `name` | string | The channel's name.                                                                                                                     |

The returned name may not be identical to the name requested, as the name will be converted to [normalization form C](http://www.unicode.org/reports/tr15/) automatically. The returned name will include this normalization; the service will use the normalized name elsewhere, and does not store the originally requested name.

When completed, the service will emit a [channel created](events.md#channel-created) event with the channel's ID.

### Name not valid

This endpoint will respond with a status of `400 Bad Request` if the proposed `name` is not valid.

### Channel name in use

This endpoint will respond with a status of `409 Conflict` if a channel with the requested name already exists.

## `POST /api/channels/:id`

Sends a message to a channel.

This endpoint requires the following path parameter:

| Parameter | Type   | Description   |
|:----------|:-------|:--------------|
| `id`      | string | A channel ID. |

### Request

```json
{
  "body": "my amazing thoughts, by bob"
}
```

The request must have the following fields:

| Field  | Type   | Description                            |
|:-------|:-------|:---------------------------------------|
| `body` | string | The message to deliver to the channel. |

### Success

This endpoint will respond with a status of
`202 Accepted` when successful. The body of the response will be a JSON object describing the newly-sent message:

```json
{
  "at": "2024-10-19T04:37:09.467325Z",
  "channel": "Cfqdn1234",
  "sender": "Uabcd1234",
  "id": "Mgh98yp75",
  "body": "my amazing thoughts, by bob"
}
```

The response will have the following fields:

| Field     | Type      | Description                                                                                                                             |
|:----------|:----------|:----------------------------------------------------------------------------------------------------------------------------------------|
| `at`      | timestamp | The moment the message was sent.                                                                                                        |
| `channel` | string    | The ID of the channel the message was sent to.                                                                                          |
| `sender`  | string    | The ID of the user that sent the message.                                                                                               |
| `id`      | string    | A unique identifier for the message. This can be used to associate the message with events, or to make API calls targeting the message. |
| `body`    | string    | The message's body.                                                                                                                     |

The returned message body may not be identical to the body as sent, as the body will be converted to [normalization form C](http://www.unicode.org/reports/tr15/) automatically. The returned body will include this normalization; the service will use the normalized body elsewhere, and does not store the originally submitted body.

When completed, the service will emit a [message sent](events.md#message-sent) event with the message's ID.

### Invalid channel ID

This endpoint will respond with a status of `404 Not Found` if the channel ID is not valid.

## `DELETE /api/channels/:id`

Deletes a channel.

Deleting a channel prevents it from receiving any further messages. The channel must be empty; to delete a channel with messages in it, delete the messages first (or wait for them to expire).

This endpoint requires the following path parameter:

| Parameter | Type   | Description   |
|:----------|:-------|:--------------|
| `id`      | string | A channel ID. |

### Success

This endpoint will respond with a status of
`202 Accepted` when successful. The body of the response will be a JSON object describing the deleted channel:

```json
{
  "id": "Cfqdn1234"
}
```

The response will have the following fields:

| Field | Type   | Description       |
|:------|:-------|:------------------|
| `id`  | string | The channel's ID. |

When completed, the service will emit a [message deleted](events.md#message-deleted) event for each message in the channel, followed by a [channel deleted](events.md#channel-deleted) event with the channel's ID.

### Channel not empty

This endpoint will respond with a status of `409 Conflict` if the channel contains messages.

### Invalid channel ID

This endpoint will respond with a status of `404 Not Found` if the channel ID is not valid.

## `DELETE /api/messages/:id`

Deletes a message.

This endpoint requires the following path parameter:

| Parameter | Type   | Description   |
|:----------|:-------|:--------------|
| `id`      | string | A message ID. |

### Success

This endpoint will respond with a status of
`202 Accepted` when successful. The body of the response will be a JSON object describing the deleted message:

```json
{
  "id": "Mgh98yp75"
}
```

The response will have the following fields:

| Field | Type   | Description       |
|:------|:-------|:------------------|
| `id`  | string | The message's ID. |

When completed, the service will emit a [message deleted](events.md#message-deleted) event with the message's ID.

### Invalid message ID

This endpoint will respond with a status of `404 Not Found` if the message ID is not valid.

### Not the sender

This endpoint will respond with a status of `403 Forbidden` if the message was sent by a different login.