# Topham
A simple client library for the [sr.ht](https://sr.ht/) REST API.
## Requirements
* [http-client](https://wiki.call-cc.org/eggref/5/http-client)
* [intarweb](https://wiki.call-cc.org/eggref/5/intarweb)
* [medea](https://wiki.call-cc.org/eggref/5/medea)
* [module-declarations](https://wiki.call-cc.org/eggref/5/module-declarations)
* [openssl](https://wiki.call-cc.org/eggref/5/openssl)
* [optimism](https://wiki.call-cc.org/eggref/5/optimism)
* [simple-exceptions](https://wiki.call-cc.org/eggref/5/simple-exceptions)
## Quick Start
Create a new job on [builds.sr.ht](https://builds.sr.ht/) and fetch
information about it:
```scheme
(import (topham)
(topham builds))
(access-token "your-access-token-goes-here")
(create (job manifest: "xyz"))
; => ((#:service "builds" #:path "/api/jobs")
; (id . 1234))
(retrieve (job 1234))
; => ((#:service "builds" #:path "/api/jobs/1234")
; (id . 1234)
; (status . "running")
; (setup_log ...)
; (tasks . #(...))
; (runner ...))
(retrieve (manifest 1234))
; => "xyz"
```
Subscribe or unsubscribe from a mailing list:
```scheme
(create (subscription list: "~sircmpwn/sr.ht-announce"))
; => ((id . 24)
; (created . "2018-07-08T23:46:31+00:00")
; (list (name . "sr.ht-announce")
; (owner (canonical_name . "~sircmpwn") (name . "sircmpwn"))))
(retrieve (subscriptions))
; => ((#:service "lists" #:path "/api/subscriptions")
; (next . null)
; (results
; .
; #(((id . 24)
; (created . "2018-07-08T23:46:31+00:00")
; (list (name . "sr.ht-announce")
; (owner (canonical_name . "~sircmpwn") (name . "sircmpwn"))))))
; (total . 1)
; (results_per_page . 50))
(delete (subscription 24))
; => #t
```
## Usage
### Authentication
There are two ways to authenticate API requests. The first is to set the
`access-token` parameter:
```scheme
(import (topham))
(access-token "...")
```
The second is to set the `SRHT_ACCESS_TOKEN` environment variable:
```scheme
(import (chicken process-context))
(set-environment-variable! "SRHT_ACCESS_TOKEN" "...")
```
If both of these are set, the parameter value is used.
### Creating Requests
This library follows a typical [CRUD][] pattern, where you (1) create a
payload representing a remote resource, then (2) send it to the server
with one of the `create`, `retrieve`, `update` or `delete` procedures.
Resources are represented as Scheme objects per [medea][]'s default
JSON-to-Scheme conversion rules. Requests and responses are represented
as association lists, where the first item specifies a remote endpoint
from which a resource should be (or has been) fetched:
```scheme
(mailing-lists)
; => ((#:service "lists" #:path "/api/lists"))
(mailing-list "foo")
; => ((#:service "lists" #:path "/api/lists/foo"))
(mailing-list name: "foo" description: "bar")
; => ((#:service "lists" #:path "/api/lists")
; (name . "foo")
; (description . "bar"))
```
Objects of this shape are referred to as "crud" throughout this
documentation.
[CRUD]: https://en.wikipedia.org/wiki/Create,_read,_update_and_delete
[medea]: https://wiki.call-cc.org/eggref/5/medea
### Pagination
Many API responses are subject to [pagination][pagination].
To specify a starting ID, use the `page` combinator. This sets the
`start` parameter for GET requests, per [sr.ht's API][pagination-api]:
```scheme
(import (only (topham) retrieve page))
; retrieve the first page of results
(retrieve (emails "~user"))
; retrieve results starting from id 42
(retrieve (page (emails "~user") 42))
```
[pagination]: https://en.wikipedia.org/wiki/Pagination
[pagination-api]: https://man.sr.ht/api-conventions.md#pagination
### API
#### topham
The `(topham)` library provides configuration parameters and procedures
for submitting CRUD requests.
[parameter] (access-token) => string
[parameter] (access-token string) => string
Sets the client's API token for authentication.
The value should be a [personal access token][tokens], which can be
created (or revoked) from your [account settings page][oauth].
This library does not support OAuth-based authentication.
[oauth]: https://meta.sr.ht/oauth
[tokens]: https://man.sr.ht/meta.sr.ht/oauth-api.md#personal-access-tokens
[parameter] (service-domain) => string
[parameter] (service-domain string) => string
Specifies the hostname of the remote service, useful for connecting to a
sr.ht instance other than .
The default value is simply `"sr.ht"`.
[procedure] (create crud) => any
[procedure] (retrieve crud) => any
[procedure] (update crud) => any
[procedure] (delete crud) => any
Submits a CRUD payload to the server.
These procedures correspond to the `POST`, `GET`, `PUT` and `DELETE`
request methods, respectively. The result is a Scheme representation of
the response (generally a "crud object"), or `#f` if the requested
resource was not found.
If the response is an error (other than HTTP 404), a condition of type
`(exn http topham)` is signaled.
[procedure] (page crud) => crud
Sets the starting ID for results fetched with `retrieve`.
Refer to [Pagination](#Pagination) for details.
#### builds
The `(topham builds)` library provides request builders for
[builds.sr.ht](https://man.sr.ht/builds.sr.ht/api.md).
[procedure] (job number) => crud
[procedure] (job #!key argument ...) => crud
In the first form, [fetches a job by ID][get-apijobsid].
In the second form, [creates a new job][post-apijobs].
`number` should be a job resource ID.
[get-apijobsid]: https://man.sr.ht/builds.sr.ht/api.md#get-apijobsid
[post-apijobs]: https://man.sr.ht/builds.sr.ht/api.md#post-apijobs
[procedure] (manifest number) => crud
[Retrieves a job's manifest][get-apijobsidmanifest].
`number` should be a job resource ID.
[get-apijobsidmanifest]: https://man.sr.ht/builds.sr.ht/api.md#get-apijobsidmanifest
[procedure] (start number) => crud
[Starts a job][post-apijobsidstart] that was created with `execute: #f`.
`number` should be a job resource ID.
[post-apijobsidstart]: https://man.sr.ht/builds.sr.ht/api.md#post-apijobsidstart
#### lists
The `(topham lists)` library provides request builders for
[lists.sr.ht](https://man.sr.ht/lists.sr.ht/api.md).
[procedure] (user string) => crud
[Retrieves a user][get-apiuserusername].
`string` should be a username or email address.
[get-apiuserusername]: https://man.sr.ht/lists.sr.ht/api.md#get-apiuserusername
[procedure] (subscriptions) => crud
[Retrieves the active user's mailing list subscriptions][get-apisubscriptions].
[get-apisubscriptions]: https://man.sr.ht/lists.sr.ht/api.md#get-apisubscriptions
[procedure] (subscription number) => crud
[procedure] (subscription #!key list) => crud
In the first form, [retrieves a subscription by ID][get-apisubscriptionssub-id].
In the second form, [subscribes to a mailing list][post-apisubscriptions].
`number` should be a subscription resource ID.
[get-apisubscriptionssub-id]: https://man.sr.ht/lists.sr.ht/api.md#get-apisubscriptionssub-id
[post-apisubscriptions]: https://man.sr.ht/lists.sr.ht/api.md#post-apisubscriptions
[procedure] (emails) => crud
[procedure] (emails string) => crud
Retrieves emails sent by the [active user][get-apiemails], or by the
[given user][get-apiuserusernameemails].
`string` should be a username or email address.
This endpoint is subject to [pagination](#Pagination).
[get-apiemails]: https://man.sr.ht/lists.sr.ht/api.md#get-apiemails
[get-apiuserusernameemails]: https://man.sr.ht/lists.sr.ht/api.md#get-apiuserusernameemails
[procedure] (email number) => crud
[Retrieves an email][get-apiemailsemail-id].
`number` should be an email resource ID.
[get-apiemailsemail-id]: https://man.sr.ht/lists.sr.ht/api.md#get-apiemailsemail-id
[procedure] (thread number) => crud
[Retrieves an email thread][get-apithreademail-id].
`number` should be an email resource ID.
This endpoint is *not* subject to pagination. Rather, the result is a
vector containing all emails in the thread.
[get-apithreademail-id]: https://man.sr.ht/lists.sr.ht/api.md#get-apithreademail-id
[procedure] (mailing-lists) => crud
[procedure] (mailing-lists string) => crud
Retrieves mailing lists belonging to the [active user][get-apilists], or
to the [given user][get-apiuserusernamelists].
`string` should be a username or email address.
This endpoint is subject to [pagination](#Pagination).
[get-apilists]: https://man.sr.ht/lists.sr.ht/api.md#get-apilists
[get-apiuserusernamelists]: https://man.sr.ht/lists.sr.ht/api.md#get-apiuserusernamelists
[procedure] (mailing-list string string) => crud
[procedure] (mailing-list string #!key description) => crud
[procedure] (mailing-list #!key name description) => crud
In the first form, [retrieves a subscription by ID][get-apiuserusernamelistslist-name].
In the second form, [updates a mailing list][put-apilistslist-name].
In the third form, [creates a mailing list][post-apilists].
The `string` arguments should be user and list names.
[get-apiuserusernamelistslist-name]: https://man.sr.ht/lists.sr.ht/api.md#get-apiuserusernamelistslist-name
[put-apilistslist-name]: https://man.sr.ht/lists.sr.ht/api.md#put-apilistslist-name
[post-apilists]: https://man.sr.ht/lists.sr.ht/api.md#post-apilists
[procedure] (posts string) => crud
[procedure] (posts string string) => crud
Retrieves posts to a mailing list, given a [list name][get-apilistslist-namepost]
or [list owner and name][get-apiuserusernamelistslist-nameposts].
In the first form, the `string` argument be a mailing list name, where
the list is assumed to belong to the active user.
In the second form, the arguments should be a username (the list owner)
and mailing list name.
This endpoint is subject to [pagination](#Pagination).
[get-apilistslist-namepost]: https://man.sr.ht/lists.sr.ht/api.md#get-apilistslist-nameposts
[get-apiuserusernamelistslist-nameposts]: https://man.sr.ht/lists.sr.ht/api.md#get-apiuserusernamelistslist-nameposts
#### meta
The `(topham meta)` library provides request builders for
[meta.sr.ht](https://man.sr.ht/meta.sr.ht/api.md).
[procedure] (profile) => crud
[procedure] (profile #!key argument ...) => crud
In the first form, [fetches the active user's profile][get-apiuserprofile].
In the second form, [updates the user's profile][put-apiuserprofile].
[get-apiuserprofile]: https://man.sr.ht/meta.sr.ht/user-api.md#get-apiuserprofile
[put-apiuserprofile]: https://man.sr.ht/meta.sr.ht/user-api.md#put-apiuserprofile
[procedure] (audit-log) => crud
[Retrieves the active user's audit log][get-apiuseraudit-log].
This endpoint is subject to [pagination](#Pagination).
[get-apiuseraudit-log]: https://man.sr.ht/meta.sr.ht/user-api.md#get-apiuseraudit-log
[procedure] (ssh-keys) => crud
[Retrieves the active user's SSH keys][get-apiuserssh-keys].
This endpoint is subject to [pagination](#Pagination).
[get-apiuserssh-keys]: https://man.sr.ht/meta.sr.ht/user-api.md#get-apiuserssh-keys
[procedure] (ssh-key number) => crud
[procedure] (ssh-key #!key ssh-key) => crud
In the first form, [fetches an SSH key by ID][get-apiuserssh-keysid].
In the second form, [creates a new SSH key][post-apiuserssh-keys].
`number` should be a key resource ID.
[get-apiuserssh-keysid]: https://man.sr.ht/meta.sr.ht/user-api.md#get-apiuserssh-keysid
[post-apiuserssh-keys]: https://man.sr.ht/meta.sr.ht/user-api.md#post-apiuserssh-keys
[procedure] (pgp-keys) => crud
[Retrieves the active user's PGP keys][get-apiuserpgp-keys].
This endpoint is subject to [pagination](#Pagination).
[get-apiuserpgp-keys]: https://man.sr.ht/meta.sr.ht/user-api.md#get-apiuserpgp-keys
[procedure] (pgp-key number) => crud
[procedure] (pgp-key #!key pgp-key) => crud
In the first form, [fetches a PGP key by ID][get-apiuserpgp-keysid].
In the second form, [creates a new PGP key][post-apiuserpgp-keys].
`number` should be a key resource ID.
[get-apiuserpgp-keysid]: https://man.sr.ht/meta.sr.ht/user-api.md#get-apiuserpgp-keysid
[post-apiuserpgp-keys]: https://man.sr.ht/meta.sr.ht/user-api.md#post-apiuserpgp-keys
#### paste
The `(topham paste)` library provides request builders for
[paste.sr.ht](https://man.sr.ht/paste.sr.ht/api.md).
[procedure] (paste string) => crud
[procedure] (paste #!key contents filename visibility) => crud
In the first form, [fetches a paste by ID][get-apipastessha].
In the second form, [creates a new paste][post-apipastes].
`string` should be a paste SHA.
[get-apipastessha]: https://man.sr.ht/paste.sr.ht/api.md#get-apipastessha
[post-apipastes]: https://man.sr.ht/paste.sr.ht/api.md#post-apipastes
[procedure] (blob string) => crud
[Fetches a blob][get-apiblobssha].
`string` should be a blob SHA.
[get-apiblobssha]: https://man.sr.ht/paste.sr.ht/api.md#get-apiblobssha
[procedure] (pastes) => crud
[Retrieves a list of pastes][get-apipastes].
This endpoint is subject to [pagination](#Pagination).
[get-apipastes]: https://man.sr.ht/paste.sr.ht/api.md#get-apipastes
## Links
* Sources:
* Issues:
* Documentation:
## License
Topham is licensed under the [3-clause BSD license][license].
[license]: https://opensource.org/licenses/BSD-3-Clause