summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
Diffstat (limited to 'docs')
-rw-r--r--docs/api.md181
1 files changed, 181 insertions, 0 deletions
diff --git a/docs/api.md b/docs/api.md
new file mode 100644
index 0000000..91e4148
--- /dev/null
+++ b/docs/api.md
@@ -0,0 +1,181 @@
+# the hi api
+
+## The basics
+
+The `hi` API is exposed as HTTP endpoints that accept JSON and return JSON on success, with a few exceptions noted below.
+
+On errors, the response body is freeform text and is meant to be shown to the user, logged, or otherwise handled. Programmatic action should rely on the status code, as documented.
+
+Requests that require a JSON body must include a `content-type: application/json` header. For requests that take a JSON body, if the body does not match the required schema, the endpoint will return a 422 Unprocessable Entity response, instead of the responses documented for that endpoint.
+
+## Authentication
+
+Other than where noted below, all endpoints require authentication.
+
+To authenticate a request, send a `cookie: identity=YOUR TOKEN HERE` header in the request. Tokens can be obtained via the `/api/auth/login` endpoint. This authentication protocol is intended to integrate with browsers and browser-like environments, where the browser handles cookie headers automatically.
+
+If the token is not valid or has expired, then `hi` will send back a 401 Unauthorized response, instead of the responses documented for the endpoint the request was intended for.
+
+## Endpoints
+
+### `GET /api/boot`
+
+Returns information needed to boot the client. Also the recommended way to check whether the current `identity` cookie is valid, and what login it authenticates.
+
+#### On success
+
+```json
+{
+ "login": {
+ "name": "example username",
+ "id": "L1234abcd",
+ }
+}
+```
+
+### `POST /api/auth/login`
+
+Authenticates the user by login name and password, creating a login if none exists. **This endpoint does not require an `identity` cookie.**
+
+#### Request
+
+```json
+{
+ "name": "example username",
+ "password": "the plaintext password",
+}
+```
+
+#### On success
+
+This endpoint returns a 204 No Content response on success, with a `Set-Cookie` header setting the `identity` cookie to a newly created token for this login. This cookie must be presented in future requests, and will authenticate the associated login.
+
+The cookie will expire if it is not used regularly. (As of this writing, identity cookies expire seven days after their last use, but this time period may change.)
+
+#### Authentication failures
+
+If the login already exists, and the provided password is different from the one used to create the login, then this will return a 401 Unauthorized response.
+
+### `POST /api/auth/logout`
+
+Invalidates the identity token, logging the user out.
+
+#### Request
+
+```json
+{}
+```
+
+#### On success
+
+This endpoint returns a 204 No Content response on success, with a `Set-Cookie` header that clears the `identity` cookie. Even if this header is not processed, the cookie provided in the request is invalidated and will not authenticate future requests.
+
+### `GET /api/channels`
+
+Lists channels.
+
+#### On success
+
+Responds with a list of channel objects, one per channel:
+
+```json
+[
+ {
+ "name": "nonsense and such",
+ "id": "C1234abcd",
+ }
+]
+```
+
+### `POST /api/channels`
+
+Creates a channel.
+
+#### Request
+
+```json
+{
+ "name": "a unique channel name"
+}
+```
+
+#### On succeess
+
+```json
+{
+ "name": "a unique channel name",
+ "id": "C9876cyyz"
+}
+```
+
+#### On duplicate channel name
+
+Channel names must be unique. If a channel with the same name already exists, this will return a 400 Bad Request error.
+
+### `POST /api/channels/:channel`
+
+Sends a chat message to a channel. It will be relayed to clients subscribed to the channel's events, and recorded for replay.
+
+The `:channel` placeholder must be a channel ID, as returned by `GET /api/channels` or `POST /api/channels`.
+
+#### Request
+
+```json
+{
+ "message": "my amazing thoughts, by bob"
+}
+```
+
+#### On success
+
+Once the message is accepted, this will return a 202 Accepted response. The message will be delivered to subscribers asynchronously, as soon as is feasible.
+
+#### Invalid channel ID
+
+If the channel ID is not valid, this will return a 404 Not Found response.
+
+### `GET /api/events`
+
+Subscribes to events. This endpoint returns an `application/event-stream` response, and is intended for use with the `EventSource` browser API. Events will be delivered on this stream as they occur, and the request will remain open to deliver events.
+
+The returned stream may terminate, to limit the number of outstanding messages held by the server. Clients can and should repeat the request, using the `Last-Event-Id` header to resume from where they left off. Events will be replayed from that point, and the stream will resume.
+
+#### Query parameters
+
+This endpoint accepts the following query parameters:
+
+* `channel`: a channel ID. Events for this channel will be included in the response. This parameter may be provided multiple times.
+
+Browsers generally limit the number of open connections, often to embarrassingly low limits. Clients should subscribe to multiple streams in a single request, and should not subscribe to each stream individually.
+
+Requests without parameters will be successful, but will return an empty stream.
+
+(If you're wondering: it has to be query parameters or something equivalent to it, since `EventSource` can only issue `GET` requests.)
+
+#### Request headers
+
+This endpoint accepts an optional `Last-Event-Id` header for resuming an interrupted stream. If this header is provided, it must be set to the `id` of the last event processed by the client. The new stream will resume immediately after that event. If this header is omitted, then the stream will start from the beginning.
+
+If you're using a browser's `EventSource` API, this is handled for you automatically.
+
+#### On success
+
+The returned event stream is a sequence of events:
+
+```json
+id: 1234
+data: {
+data: "channel": "C9876cyyz",
+data: "id": "Mabcd1234",
+data: "sender": {
+data: "id": "L1234abcd",
+data: "name": "example username"
+data: },
+data: "body": "my amazing thoughts, by bob",
+data: "sent_at": "2024-09-19T02:30:50.915462Z"
+data: }
+```
+
+The event `id` (`1234`, in the example above) is used to support resuming the stream after an interruption. See the "Request headers" section, above, for details.
+
+The `"id"` field uniquely identifies the message in related API requests, but is not used to resume the stream.