209 lines
8.4 KiB
Markdown
209 lines
8.4 KiB
Markdown
# README
|
|
|
|
This is the REST API server for the online Paco Ŝako chess variation front-end
|
|
provided by the [paco-sako](https://jessemcdonald.info/gogs/nybble/paco_sako) package.
|
|
The server stores game data in a SQLite3 database
|
|
and exposes interfaces for immediate queries, long-polling, and POST updates.
|
|
The listening port is configurable and HTTPS is supported with a certificate file.
|
|
|
|
## Invocation
|
|
|
|
```
|
|
node ./server.js [PORT]
|
|
```
|
|
|
|
or
|
|
|
|
```
|
|
npm start [PORT]
|
|
```
|
|
|
|
## Environment Variables
|
|
|
|
### `OPENSHIFT_NODEJS_PORT`, `VCAP_APP_PORT`, or `PORT`
|
|
|
|
If any of these variables are defined
|
|
then the first one encountered determines the listening port,
|
|
overriding any port specified on the command line.
|
|
The default port is 8765 if no environment variable is defined
|
|
and no port is given on the command line.
|
|
|
|
### `HTTPS_KEY` and `HTTPS_CERT`
|
|
|
|
If the `HTTPS_KEY` environment variable is defined
|
|
then the server operates in HTTPS mode
|
|
using the key found in the file named by `HTTPS_KEY`
|
|
and the certificate found in the file named by `HTTPS_CERT`.
|
|
If `HTTPS_KEY` is set then `HTTPS_CERT` is also required.
|
|
|
|
## JSON Schema
|
|
|
|
Most APIs either accept or return a JSON "game data" object
|
|
with some or all of the following fields:
|
|
|
|
* `gameId`: String. Sixteen hexadecimal characters.
|
|
The randomly-generated code which uniquely identifies a game.
|
|
|
|
* `lightName`: String. The name of the player controlling the light pieces.
|
|
|
|
* `darkName`: String. The name of the player controlling the dark pieces.
|
|
|
|
* `moves`: Integer. The number of partial *or* completed *turns* in the current game.
|
|
Also the number of times the light player has started a move.
|
|
(The use of the name `moves` rather than `turns` is a historical artifact.)
|
|
|
|
* `status`: String. A short string which describes the current state of the game,
|
|
for example the current player if the game is ongoing or the winner otherwise.
|
|
This string appers in the game selection list.
|
|
|
|
* `timestamp`: Integer. The UTC time in milliseconds of the most recent move.
|
|
Typically the same as the `timestamp` metadata for the last move in `board.past`,
|
|
or the time when the metadata was most recently updated if there are no moves.
|
|
The timestamp can decrease, for example in response to a player undoing a move.
|
|
|
|
* `board`: Object. An arbitrary JSON object provided by the front-end
|
|
to describe the current state of the game.
|
|
The object is not validated by the server at present
|
|
but it typically includes two fields, `past` and `future`,
|
|
which are arrays of objects respectively representing the moves completed thus far
|
|
and (in reverse order) any moves which were undone, to support the redo operation.
|
|
This object is stored in the database as a JSON-encoded string.
|
|
|
|
* `modified`: Integer. The modification time of the record as determined by the server.
|
|
This is normally a UTC time in milliseconds but the server adjusts the value
|
|
to ensure that updates have modification times which are strictly greater than
|
|
any modification times previously stored in the database.
|
|
|
|
The "metadata" fields are all the fields listed above except `board`.
|
|
The `board` field is potentially large and consequently is omitted
|
|
from the responses for certain APIs.
|
|
|
|
Fields which are either NULL or equal to an empty string are not included
|
|
in game objects returned from the REST APIs.
|
|
|
|
The following data is stored in the database but not included in any REST API:
|
|
|
|
* `added`: The value of the `modified` field at the point where the game
|
|
record was first inserted into the database.
|
|
|
|
## REST APIs
|
|
|
|
### `GET /pacosako/api/games`
|
|
|
|
Returns the list of active games.
|
|
A game is considered "active" if the `timestamp` field indicates that
|
|
either the game was started or the last move was played
|
|
within the past two weeks according to the server's clock.
|
|
The successful JSON response consists of two fields,
|
|
`games` which is an array of game objectsi
|
|
in descending order by their `timestamp` fields,
|
|
and `modified` which is the maximum value of the `modified` fields
|
|
of all of the games in the `games` array,
|
|
or zero if the array is empty.
|
|
The objects in the `games` array include
|
|
all of the game object fields described above
|
|
*except* the `board` field.
|
|
|
|
### `GET /pacosako/api/games/poll/:afterTime`
|
|
|
|
Parameters:
|
|
|
|
* `afterTime`: Integer.
|
|
Any record with a `modified` field less than or equal to this value
|
|
is excluded from the results.
|
|
|
|
Equivalent to the `GET /pacosako/api/games` API with two exceptions.
|
|
First, it excludes games with older `modified` times from the results.
|
|
Second, if there are no results which match this criteria
|
|
then the server waits up to one minute for the situation to change
|
|
before responding with a 204 status code.
|
|
It is expected that the client will respond to a 204 status
|
|
by repeating the request.
|
|
If a game is updated during the waiting period
|
|
then the server will respond immediately with the new information.
|
|
|
|
The `afterTime` parameter will normally match the `modified` field
|
|
from the most recent successful response to either
|
|
`GET /pacosako/api/games` or `GET /pacosako/api/games/poll/:afterTime`.
|
|
|
|
### `GET /pacosako/api/game/:gameId`
|
|
|
|
Parameters:
|
|
|
|
* `gameId`: String. Identifies the game object to be returned.
|
|
|
|
On success this API returns the complete game object for the given `gameId`,
|
|
which must be a 16-character hexadecimal string.
|
|
If there is no record matching the given gameId then a 404 status code is returned.
|
|
|
|
### `GET /pacosako/api/meta/:gameId`
|
|
|
|
This API is identical to `GET /pacosako/api/game/:gameId` except that the
|
|
`board` field is omitted from the response.
|
|
|
|
### `GET /pacosako/api/game/:gameId/poll/:afterTime`
|
|
|
|
Parameters:
|
|
|
|
* `gameId`: String. Identifies the game object to be returned.
|
|
|
|
* `afterTime`: Integer. The response must be a game object
|
|
with a `modified` field strictly greater than this value.
|
|
|
|
Equivalent to the `GET /pacosako/api/game/:gameId` API except that
|
|
if there is no record with a matching `gameId`
|
|
or the record has a `modified` field less than or equal to the `afterTime` parameter
|
|
then the server waits up to one minute for the situation to change
|
|
before responding with a 204 status code.
|
|
It is expected that the client will respond to a 204 status by repeating the request.
|
|
If the game is created or updated during the waiting period
|
|
then the server will respond immediately with the new information.
|
|
Unlike the non-polling version,
|
|
this API does not return a 404 status code when the `gameId` does not exist.
|
|
|
|
The `afterTime` parameter will normally match the `modified` field
|
|
from the most recent successful response to either
|
|
`GET /pacosako/api/game/:gameId` or `GET /pacosako/api/game/:gameId/poll/:afterTime`.
|
|
|
|
### `GET /pacosako/api/meta/:gameId/poll/:afterTime`
|
|
|
|
This API is identical to `GET /pacosako/api/game/:gameId/poll/:afterTime`
|
|
except that the `board` field is omitted from the response.
|
|
|
|
### `POST /pacosako/api/game/:gameId`
|
|
|
|
Parameters:
|
|
|
|
* `gameId`: String. Identifies the game object to be updated.
|
|
|
|
The JSON-encoded request body for this API should consist of a subset of a game object
|
|
which includes the `modified` field and at least one other field to be updated.
|
|
The `modified` field in the request must match
|
|
the *current* version of the record in the database
|
|
for the update to be successful, if such a record exists;
|
|
this serves as a form of locking to prevent race conditions
|
|
between multiple clients updating the same game record.
|
|
The `modified` field of the new version of the record on success
|
|
will be determined by the server.
|
|
If there is no existing version of the record then
|
|
value of the `modified` field in the request is not used;
|
|
however, the field is still required.
|
|
It is recommended that a `modified` value of zero be used
|
|
when initializing a new game
|
|
since this value is guaranteed not to match any existing game record.
|
|
|
|
A 400 status will be returned if the request body does not follow the expected schema.
|
|
If the `modified` field does not match the `modified` field in the database
|
|
*and* the value of any other field in the request does not match
|
|
the current version of the data in the database
|
|
then a 409 response is returned with a `message` string field describing the error
|
|
and the `modified` field from the current version of the record in the database.
|
|
Otherwise the POST request succeeds with a status code of 200
|
|
and the response body consists of a `success` field with the value `true`
|
|
and the `modified` field of the new version of the record.
|
|
|
|
### `POST /pacosako/api/meta/:gameId`
|
|
|
|
This is an alias for the `POST /pacosako/api/game/:gameId` API.
|
|
Either API can be used to update any field, including `board`.
|