Select
A select endpoint is a read: it returns a table of records from one collection. It narrows the collection with a filter, can take typed parameters from the query string, sorts and limits the result, and chooses which columns to return, optionally under public names. It is the datahoster-endpoint-select.json file in an endpoint folder; its presence makes that endpoint answer a GET.
{
"datahoster-endpoint-select-collection": "messages",
"datahoster-endpoint-select-columns": [
{
"datahoster-endpoint-select-column-of": "name",
"datahoster-endpoint-select-column-as": "sender"
},
{
"datahoster-endpoint-select-column-of": "message"
}
],
"datahoster-endpoint-select-parameters": [
{
"datahoster-endpoint-select-parameter-name": "since",
"datahoster-endpoint-select-parameter-type": "number"
}
],
"datahoster-endpoint-select-filter": [
["at", "ge", { "param": "since" }]
],
"datahoster-endpoint-select-sort": [
["at", "desc"]
],
"datahoster-endpoint-select-limit": 100,
"datahoster-endpoint-select-public": false,
"datahoster-endpoint-select-users": ["you"]
}
since, newest first, readable only by you.Contents
The file is one JSON object; its keys are fixed names starting with datahoster-endpoint-select-. The example above, in an inbox/ endpoint, reads messages since a given time, newest first, readable only by you.
| Name | Type | Description |
|---|---|---|
datahoster-endpoint-select-collection | text | The collection this endpoint reads. Required. |
datahoster-endpoint-select-columns | array | The columns to return, each optionally renamed. Defaults to every column. |
datahoster-endpoint-select-parameters | array | Typed inputs the caller supplies in the query string. Optional. |
datahoster-endpoint-select-filter | array | Conditions a record must all match. Optional. |
datahoster-endpoint-select-sort | array | A list of [column, "asc"|"desc"] keys over the in-memory columns, applied in order. Optional. |
datahoster-endpoint-select-limit | integer | The most records to return. The server also caps every read. Optional. |
datahoster-endpoint-select-public | boolean | Whether anyone may call it, with no token. Defaults to false. |
datahoster-endpoint-select-users | array | The users who may call it, each proving a token. Defaults to []. |
datahoster-endpoint-select-columns
The columns to return, in order. Each element names a collection column with -column-of and may give it a public name with -column-as; without -as, the column's own name is used. A column the filter tests need not be listed here, so you can filter on a column you do not return.
| Name | Type | Description |
|---|---|---|
datahoster-endpoint-select-column-of | text | The column of the collection to return. Required. |
datahoster-endpoint-select-column-as | text | The name it takes in the response. Defaults to the column's own name. |
datahoster-endpoint-select-parameters
Typed inputs the caller supplies in the query string. A filter condition binds one with { "param": "name" } in place of a literal. A parameter with a -parameter-default is optional and falls back to that value; one without is required, and omitting it is a 400. A supplied value is coerced to the parameter's type.
| Name | Type | Description |
|---|---|---|
datahoster-endpoint-select-parameter-name | text | The query-string key the caller supplies. Required. |
datahoster-endpoint-select-parameter-type | text | Any column type. The supplied value is coerced to it. Required. |
datahoster-endpoint-select-parameter-default | the parameter's type | A default value. Its presence makes the parameter optional. Optional. |
datahoster-endpoint-select-filter
A list of conditions, each [column, op, value] over a column of the collection. The value is a literal or { "param": "name" } to bind a parameter. A record is returned only if it matches all conditions. The value is compared with the record's typed value, so ["handled", "eq", false] tests the boolean, not the string.
A filter tests the columns the server holds in memory: the numeric columns (integer, number, boolean, int128), the fixed-size char columns (char8 to char1024), and the automatic id, at and by. A text column keeps its value on disc and cannot be filtered or sorted, and every column named in a filter, sort, returned-column, field or forced value must exist — an endpoint that filters or sorts on a text column, or names a column its collection does not have, fails to sync with a message naming the endpoint and column. The contains and prefix operators match on bytes, so they apply to a char column (and to by).
| Op | Keeps a record when its column is… |
|---|---|
eq | equal to the value |
ne | not equal to the value |
lt / le | less than / at most the value |
gt / ge | greater than / at least the value |
contains | a char value that contains the value's bytes |
prefix | a char value that starts with the value's bytes |
HTTP request
GET the endpoint's path, at <domain>/<endpoint>, supplying each declared parameter as a query-string value. If the endpoint is not public, send the user's token as a bearer token. The response is a JSON array of records, each an object under the public column names. A request that is not allowed — no token where one is needed, a wrong token, or a user this endpoint does not list — gets the same 404 as a path with no endpoint.
GET https://api.example.com/inbox?since=1782864000000
Authorization: Bearer k7Qw2f9xJ4mB6pR8tZ1nD3sV5hL0aYc
inbox endpoint as you, since a millisecond time.| Status | Meaning |
|---|---|
200 | A JSON array of matching records, with an ETag header. |
304 | The request carried a matching If-None-Match and the result has not changed, so no body is sent. |
400 | A required parameter is missing, or a value fails its type. |
404 | No select endpoint answers on this path, or the caller is not allowed it — a missing token, an invalid one, or a user the endpoint does not list. The two are indistinguishable, so a probe cannot tell the endpoint is there. |
Change detection
Every select response carries an ETag: a short tag that stands for exactly the rows the endpoint returned. It changes whenever an insert, update or delete alters that result, and stays the same when nothing in the result moved, even if the rest of the collection changed. So a caller can tell whether a view is worth re-reading without downloading it.
There are two ways to use it. Send the last tag back in If-None-Match on a GET and the server answers 304 Not Modified, with no body, when the result is unchanged. Or send a HEAD to get the current tag on its own. A browser does the first automatically, so a page that fetches the endpoint re-downloads it only when it has really changed; a build script or a site's search box can use either.
HEAD https://api.example.com/list
ETag only, no body.GET https://api.example.com/list
If-None-Match: "fef5c63a045d0b1ecd11f228"
304 when the result has not changed since that tag.