The handshake is required before any requests can be served. If the first message sent cannot be parsed as a handshake, the connection will be dropped. The handshake will be used to associate the client with a specific user (and set of security rules) on the server. This should be extensible in the same way as #12.
For now let's just leave this a placeholder, since we haven't gotten to authentication yet.
{
"request_id": <NUMBER>,
"method": "unauthenticated" | "anonymous" | "token",
"token": <STRING>,
}
request_id
is a number uniquely identifying this request, it will be returned in the response.method
designates the type of authentication to be performed.unauthenticated
performs no further steps and will not associate the connection with any user.anonymous
will create a new account with no external authentication provider.token
will associate the connection with the user in the horizon access token provided.
token
is the horizon access token that the client must already possess.- This field is required when
method
istoken
, and invalid otherwise.
- This field is required when
{
"request_id": <NUMBER>,
"token": <STRING>
}
token
is the horizon access token that is associated with this connection.- This token may be used to establish new connections under the same user account until the token expires.
{
"request_id": <NUMBER>,
"error": <STRING>,
"error_code": <NUMBER>
}
All requests match the following pattern:
{
"request_id": <NUMBER>,
"type": <STRING>,
"options": <OBJECT>
}
request_id
is a number uniquely identifying this request, it will be returned in any responsestype
is the endpoint for the query - one ofquery
,subscribe
,store_error
,store_replace
,update
, orremove
.options
is an object structured differently for each endpoint.
{
"request_id": <NUMBER>,
"type": "query" | "subscribe",
"options": {
"collection": <STRING>,
"order": [ <ARRAY>, "ascending" | "descending"],
"above": [ <OBJECT>, "open" | "closed" ],
"below": [ <OBJECT>, "open" | "closed" ],
"find": <OBJECT>,
"find_all": [<OBJECT>, ...],
"limit": <NUMBER>,
}
}
collection
describes which table to operate on in the horizon database.order
orders the results according to an array of fields - optional.- The first argument is an array of field names, most-significant first.
- The second argument determines which direction the results are sorted in.
above
andbelow
are arrays describing the boundaries regardingorder
- optional.above
andbelow
can only be specified iforder
is provided.- The first argument is an object whose key-value pairs correspond to fields in
order
. - The second argument should be
closed
to include the boundary, andopen
otherwise.
find
returns one object incollection
that exactly matches the fields in the object given - optional.find
cannot be used withfind_all
,order
,above
, orbelow
.
find_all
is an array of objects whose key-value pairs correspond to keys inindex
- optional.- Returns any object in
collection
that exactly matches the fields in any of the objects given. find_all
cannot be used withfind
.find_all
with multiple objects cannot be used withorder
,above
, orbelow
.
- Returns any object in
limit
limits the number of results to be selected - optional.
{
"request_id": <NUMBER>,
"type": "store" | "update" | "upsert" | "insert" | "replace" | "remove",
"options": {
"collection": <STRING>,
"data": [<OBJECT>, ... ]
}
}
collection
describes which table to operate on in the horizon databasedata
is the documents to be written (or removed)data[i].id
is required forremove
operations, all other fields are optionaldata[i].id
may be omitted in aninsert
,store
, orupsert
operations: a new row will be inserted in the collection
type
is the write operation to performinsert
inserts new documents, erroring if any document already existsupdate
updates existing documents. It errors if any document does not already existupsert
updates existing documents or inserts them if they do not existreplace
replaces existing documents entirely. It errors if any document does not already existstore
replaces existing documents entirely, or inserts them if they don't exist.remove
removes documents. It will not error if a document does not exist
Tells the horizon server to stop sending data for a given subscription. Data may still be received until the server has processed this and sent a "state": "complete"
response for the subscription.
{
"request_id": <NUMBER>,
"type": "end_subscription"
}
This is used by the client to perform an empty request to avoid connection interruption.
{
"request_id": <NUMBER>,
"type": "keepalive"
}
This can be sent for any request at any time. Once an error response is sent, no further responses shall be sent for the corresponding request_id
.
{
"request_id": <NUMBER>,
"error": <STRING>,
"error_code": <INTEGER>
}
request_id
is the same as therequest_id
in the corresponding requesterror
is a descriptive error stringerror_code
is a code that can be used to identify the type of error, values TBD
query
and subscribe
requests will result in a stream of results from the horizon server to the client. The stream will be an ordered set of messages from the server following the structure below. If an error occurs, the above Error Response structure will be used, and the stream is considered "complete". An Error Response may still be sent even after a successful data response, but not after "state": "complete"
.
{
"request_id": <NUMBER>,
"data": <ARRAY>,
"state": "synced" | "complete"
}
request_id
is the same as therequest_id
in the corresponding requestdata
is an array of results for thequery
orsubscribe
, and may be emptystate
is optional, and indicates a change in the stream of data:synced
means that following the consumption ofdata
, the client has all the initial results of asubscribe
complete
means that following the consumption ofdata
, no more results will be returned for the request
store
, replace
, insert
, update
, upsert
, and remove
requests will be given a single response. This may be an Error Response, or:
{
"request_id": <NUMBER>,
"data": [ { "id": <DOCUMENT_ID>, "$hz_v$": <DOCUMENT_VERSION> } | { "error": <STRING>, "error_code": <INTEGER> }, ...],
"state": "complete"
}
data
is an array of objects corresponding to the documents specified in the write (whether or not a change occurred). For inserted documents it will be the id generated by the server as well as the latest version field for the affected document. If an error occurred, there will instead be an error description string and an error code in the object . The items in the array correspond directly to the changes in the request, in the same order.state
can only be "complete" for write responses
keepalive
requests will be given a single response. This will never be an error response unless there is a protocol error.
{
"request_id": <NUMBER>,
"state": "complete"
}