Node Server API

This page describes the API for building Node-based services

Contents

Installation

In order to build Node-based Lever services, there is no need to install any external library. You simply define a JavaScript module which exports the methods that you want to expose as part of the service's API. The methods are simply JavaScript functions which are called whenever the respective methods are invoked.

Methods that start with _ are considered internal (even if they are exported by the module) and are ignored by Lever.

To use Node as the method handler, set the jsEntry property in lever.json to the name of the module where the methods are implemented. Example

{
  "name": "exampleService",
  "jsEntry": "service.js"
}

Using third-party libraries

You are free to use any third-party JavaScript library as part of your service implementation. If the libraries contain non-JavaScript sources (such as C++ Node bindings, it recommended to install the dependencies in a Lever container before deploying the service (along with node_modules) onto Lever. To achieve this, use the following (rather than the usual npm install).

$ docker run --rm -it --user=root -v "$PWD":/leveros/custcode leveros/levercontainer:latest npm install

An example of a library that requires this procedure is our own leveros client library.

Defining regular (non-streaming) methods

For non-streaming methods, the signature of each function is

➡️ module.exports.<method> = function ([resource], [args...], callback)

Where

  • is the name of the method.
  • resource is a string representing the name of the resource invoked, if any. This argument is not provided if the resource is not set or is "".
  • args... are the individual invokation arguments of the method. If the method takes JSON args, then each arg will be available here, in decoded form. If the method takes byte args, then a single arg, of type Buffer will be provided.
  • callback is the invokation async callback that needs to be called to send back a response (or an error).

A very basic example of such a method is as follows.

module.exports.sayHello = function (arg1, arg2, callback) {
  callback(null, "Method invoked with args " + arg1 + " and " + arg2 + ".");
};
{
  "name": "exampleService",
  "jsEntry": "service.js"
}

Defining streaming methods

For streaming methods, the signature of each function is

➡️ module.exports.<method> = function (stream, [resource], [args...])

Where

  • is the name of the method. For streaming methods, the name must end with Chan or _chan.
  • stream is an instance of a Stream object (see below). This object is used to communicate with the client.
  • resource is a string representing the name of the resource invoked, if any. This argument is not provided if the resource is not set or is "".
  • args... are the individual invokation arguments of the method. If the method takes JSON args, then each arg will be available here, in decoded form. If the method takes byte args, then a single arg, of type Buffer is provided.

A very basic example of such a method is as follows.

module.exports.helloChan = function (stream, salutation) {
  // This is invoked on errors.
  stream.on('error', function (error) {
    console.log(error);
    stream.end();
  });
  // This is invoked on each message received from the client.
  stream.on('data', function (msg) {
    stream.write(salutation + ", " + msg.name + "!");
  });
  // This is invoked when the client stops sending.
  stream.on('end', function () {
    stream.end();
  });
};
{
  "name": "exampleService",
  "jsEntry": "service.js"
}

🔖 Class: Stream

An instance of the Stream class is passed as the first parameter to streaming method handlers. It is used to send and receive messages to/from the client.

↘️ Event: data

  • message. If the message is of type JSON, then this will be the decoded message. If the message if of type bytes, then this will be a instance of Buffer containing the bytes.

Emitted when the server receives a message from the client.

↘️ Event: end

Emitted when the client closes its end of the stream. Even though the client will no longer send messages, the server may yet continue to send messages for the client to consume.

↘️ Event: error

  • error. The Error received.

Emitted when there is an error with the stream. Either the client has sent an error or there was a problem with the underlying connection.

➡️ end()

Ends the invokation. After this method is called, the server will no longer send or receive messages to/from the client.

➡️ write(message)

Sends a message to the client. The message can be either a serializable JavaScript value or a Buffer object.