Unichat WebSocket API


To access WebSocket api, first include somewhere in your HTML page the script to load the an Javascript API library from unichat site:

<script src="https://chat.universa.io/api/chat.js"></script>

It will load interface object you'll use to access unichat API functions and in turn provide your own functions for remote calls, such as notifications and error reportings.1

To start working, create unichat api object with:

val api = UniversaChatApi(settings, localInterface);

The settings object must contain at least { token: "test_token1 } field. The real token value you'll get from the service administration or with future service registration procedure. This function should only be called once, the lost connection will be restored automatically, watch the localInterface callbacks for it.

The localInterface is an object providing callbacks for API events. You need not implement all the callbacks and remote-callable procedures, only these you need. For example:

val api = UniversaChatApi(
        {
            token: "test_token1"

        },{
            function onSocketConnected() {
                console.log("<> connected event consumed");
            },
            function onDisconnected() {
                console.log("<> disconnected event consumed");
            },
            function onInitialized() {
                console.log("<> onInitialized called, api:", api);
                api.ping({string: "hello1"}).then((result) => {
                    console.log("<> ping returns " + result.pong);
                }).then(() => {
                    return api.version();
                }).then((version) => {
                    console.log("api_version: " + version.version);
                }).catch((reason) => {
                    console.log("<> FAILED call: " + reason);
                });
            }
        }

Now let's see it in depth.

Important! Client software must properly handle reconnection. The API library will reconnect on itself, but the new connection looses log in state and software must then log in again using auth_token, without prompting the user.

We recommend to do it in onInitialized() handler: check that there is login token stored in the memory or lcal store, and login at this point. Note that you can not yet do in in onSocketConnected() as the protocol may not be ready.

Settings

The only settings needed for the API user is token that should be set to your application's token.

Local interface

It's an object that provide a callback for the events and server-called procedures you need. When the server calls the local interface procedure that is not implemented, it just writes it to the log.

The following table shows some events and server-caller procedures:

name type description
onSocketConnected local event the socket connection is established, but the local identity is not yet checked and API protocol is not ready. Do not call any API methods at this point
onDisconnected local event the websocket connection is dropped for any reason. Do not call any API method after this call
onInitialized server call the server side is ready to execute any API methods. This is a local interface tgat server calls when it's ready

UniChat API object

The object returned by the UniversaChatApi is a main entry point to call API methods. Among direct functional access to the remote methods it provides has fields:

field name description
appToken the application token used to connect to the API
localInterface the interface provided on aPI object construction
callByName method to call any API function by its name

Remote interface

The api object explained above provides direct access to all unichat API methods just like ordinary javascript functions, which takes the single hash-like argument with named parameters of the call and return the Promise object which will pass result in the same named parameters hash with value, returned from the service.

For example, from our sample above:

api.ping({string: "hello1"}).then((result) => {
    console.log("<> ping returns " + result.pong);
}).then( () => {
    return api.version();
}).then( (version) => {
        console.log("api_version: " + version.version);
});

Does the following:

  • calls ping(string: <string>) -> {pong: <string>} unichat API method which returns pong string value
  • if it is ok, calls version() -> {version: string,...} method and display version string.

So, in general, if the unichat API provides some function described as

do_something(foo: <string>,bar: <int>) -> {bazz: string}

It should be called through api object as:

await doSomething({foo: "FOO", bar: 11})

where await is allowed, or by processing the returned Promise, where it is not.

Notice that method names you can use as both camelCase or snake_case, the interface will convert it automatically. Instead, the case of arguments and returned parameters is always same as stated in declaration.

Errors

There are two flavors of errors: remote errors reported by the API and local errors caused by, for example, disonnected websocket. While both are reported with rejected promise, the rejection object is different.

Reporting error from API

If the service call returns error, the promise will be rejected with the following data:

{
    class: exceptionClassName, // allow some extra diagnostics
    code: string, // error code string, fixed
    text: string  // human-readable description, may vary
}

Usually, calling party should interpret only code data, leaving text message just to simplify debugging process.

Se the sample above for catching promise rejection with unichat API error information.

Reporting local error

When local library fails to call remote API, it rejects the promise with an custom UniversaError exception object instance, which text represents the error reason. As for now it could be:

  • disconnected: command can't be excuted because of the connection absence. It is reported when the command being executed is interrupted by the connectino loss, or immediately if the api is called when the connection is not established.

Calling method by name

We discourage this approach, still it is possible to call any API method by name rather than directly. You should keep in mind that the ambiguity in your code reduces cleanness and readability of your code, hence increasing the support (and owning) costs of your project, this shortens its life and in a large perspective does no good to your record.

api.callByName(name, args={});
  • name: string method name, with the same conversions applied as to the regular method name.
  • args: hash of named parameters.

This method also returns the Promise which resolves to the possibilty hash of named parameters that might be returned by the server.