@hitchy/plugin-odem-socket.io
v0.3.0
Published
exposing Hitchy's document-oriented database via websocket
Downloads
75
Readme
@hitchy/plugin-odem-socket.io
exposing Hitchy's document-oriented database via websocket
License
Installation
npm i @hitchy/plugin-odem-socket.io
This plugin relies on additional plugins to be installed as well:
npm i @hitchy/plugin-odem @hitchy/plugin-socket.io
Breaking changes
v0.2
- The parameter
uuidsOnly
of actions<modelName>:list
and<modelName>:find
has been replaced byloadRecords
to match the semantics of server-side Odem API. You have to negate its value to adapt.
v0.3
- This version is recognizing an existing authentication plugin and checks a user's authorization for accessing models and their properties based on authorization rules set on server.
- Previously, actions of control API required the provision of a session ID to read a requesting user from as first argument. This approach has been abandoned. All actions are automatically associated with the user which has been authenticated when the websocket connection has been established.
- Clients should drop and re-connect over websocket whenever authentication of a requesting user has changed.
Usage
Basics
This plugin is exposing an API via websocket for controlling and monitoring models of server-side document-oriented database. Relying on particular features of socket.io, this API is exposed in namespace /hitchy/odem
.
For every server-side model, request listeners and/or notification broadcasters are set up. Either model's name is converted into its kebab-case variant and used as colon-separated prefix in event names emitted either by the server or by a client.
In the following sections, the placeholder
<modelName>
is used instead of that kebab-case variant of a model's name.
Control API
Attention!
As of v0.1.0, the control API is disabled by default due to the lack of having authorization checks implemented on server-side. You have to enable it explicitly by setting runtime configuration parameter
config.socket.odem.crud
which defaults tofalse
.
All action events listed in this section are to be sent by a client. The server is setting up listeners and directly responds to either received event. Thus, the common pattern on client side looks like this:
const socket = io( "/hitchy/odem" );
socket.on( "connect", () => {
socket.emit( actionName, arg1, arg2, arg3, response => {
// process the response here
} );
} );
socket.io requires all arguments to be provided no matter what. Thus, you can't omit any of the arguments given in examples below but have to provide values assumed to be default, at least.
The following code excerpts are focusing on the inner part of emitting an action event and processing the response.
<modelName>:list
This request is the websocket variant of Model.list(). Supported arguments are
query-related options as supported by
Model.list()
anda boolean controlling
loadRecords
of result-related options supported byModel.list()
.This boolean must be
true
to actually get the properties of retrieved items. Otherwise, listed items are represented by their UUIDs, only.
socket.emit( "<modelName>:list", { limit: 10 }, false, response => {
// - check for `response.success` or `response.error`
// - process total count of items in `response.count`
// - process requested excerpt of items in `response.items`
} );
Last argument is a callback to be invoked with the resulting response from server-side. response
is an object consisting of truthy property success
on success or error
message in case of a failure. On success, property count
is providing total count of matches and items
is the list of matching items' properties.
<modelName>:find
This request is searching for instances of selected model matching some query. It is invoking Model.find(). Arguments are
the query describing items to find,
query-related options as supported by
Model.find()
anda boolean controlling
loadRecords
of result-related options supported byModel.find()
.This boolean must be
true
to actually get the properties of retrieved items. Otherwise, listed items are represented by their UUIDs, only.
socket.emit( "<modelName>:find", {}, { limit: 10 }, true, response => {
// - check for `response.success` or `response.error`
// - process total count of items in `response.count`
// - process requested excerpt of items in `response.items`
} );
Last argument is a callback to be invoked with the resulting response from server-side. response
is an object consisting of truthy property success
on success or error
message in case of a failure. On success, property count
is providing total count of matches and items
is the selected excerpt from that list of matching items' each given by its properties including its UUID.
<modelName>:create
This request is creating another instance of selected model assigning provided properties as initial values. Those properties are provided as serializable object.
socket.emit( "<modelName>:create", { title: "important things" }, response => {
// - check for `response.success` or `response.error`
// - process properties of eventually created instance in `response.properties`
// - created instance's UUID is available as `response.properties.uuid`
} );
Last argument is a callback to be invoked with the resulting response from server-side. response
is an object consisting of truthy property success
on success or error
message in case of a failure. On success, properties
of created instance are returned. These may be different from provided ones due to server-side constraints. The created item's UUID is added to that set of properties as uuid
.
<modelName>:read
This request is fetching a single instance's properties.
socket.emit( "<modelName>:read", "12345678-1234-1234-1234-123456789012", response => {
// - check for `response.success` or `response.error`
// - process properties of fetched instance in `response.properties`
} );
Last argument is a callback to be invoked with the resulting response from server-side. response
is an object consisting of truthy property success
on success or error
message in case of a failure. On success, properties
of selected instance are returned.
<modelName>:update
This request is updating an existing instance of model. The UUID of item to update and the values per property to assign are provided as arguments.
socket.emit( "<modelName>:update", "12345678-1234-1234-1234-123456789012", { prio: 1 }, response => {
// - check for `response.success` or `response.error`
// - properties of updated instance are provided in `response.properties`
} );
Last argument is a callback to be invoked with the resulting response from server-side. response
is an object consisting of truthy property success
on success or error
message in case of a failure. On success, properties
of updated instance are returned. These may be different from provided ones due to server-side constraints.
<modelName>:delete
This request is eventually completing the CRUD-support of this API by deleting an existing instance of model selected by its UUID in first argument.
socket.emit( "<modelName>:delete", "12345678-1234-1234-1234-123456789012", response => {
// - check for `response.success` or `response.error`
// - deleted instance's UUID is available as `response.properties.uuid`
} );
Last argument is a callback to be invoked with the resulting response from server-side. response
is an object consisting of truthy property success
on success or error
message in case of a failure. On success, properties
of updated instance are returned.
Notifications
notifications of the document-oriented database are forwarded as broadcast events named <modelName>:changed
. Either event consists of
- a type of change and
- the changed item's properties (limited to its UUID on deletion).
The type of change is
created
on notifications about having created another instance of model,updated
on notifications about having adjusted one or more properties of an existing instance of model anddeleted
on notifications about having removed an existing instance of model.
In last case the provided set of properties is limited to the instance's UUID. The common pattern on client-side for listening to server-side notifications looks like this:
const socket = io( "/hitchy/odem" );
socket.on( "<modelName>:changed", info => {
// type of change is in `info.change`, e.g. "updated"
// process properties of changed instance in `info.properties`
} );
There may be server-side restriction applying per event or per instance of model, thus some or all notifications might be omitted.