Auto Client API
This feature comes from a common use of the Node.js BAL where service writers create a client module that other services can use to more easily make bus calls to their service. These client modules tend to duplicate a lot of code that could be easily abstracted away into a single automatically generated client API.
Creating a Client API
bal.client: (serviceType: String, defaultRealm: String, serviceVersion: Number) => Prototype
Client APIs are created by defining a prototype with a set of operations that will be available to users. When a prototype is initialized by the user, those operation definitions provide a client API that can be used to interact with specific services more easily. With a good client API, users of your service can avoid simple mistakes that occur during direct Bus calls and will be somewhat shielded from deprecations and API changes in the future.
The prototype file can be distributed by simply exporting the initialization function, along with whatever else is needed to support the API (constants, etc.).
1 | // <calculator_prototype.js> |
Automatic Operations
prototype.auto: (operationName: String) => Prototype
prototype.auto: (operationNames: Array<String>) => Prototype
Within our prototype definition, we can automatically generate operations from a list of names using prototype.auto:
1 | // All at once, |
These operations will be automatically implemented on an initialized client as both client.op and client._op and will have the following signature:
1 | op(callback) |
For example, to send an add request with the automatic operation, a user could do something like this:
1 | client.add({ num1: 2, num2: 3}, function (errs, results, context) { |
Redefining Operations
prototype.op: (opName: String, opDefinition: Function) => Prototype
prototype.ops: (opDefinitions: Map<String, Function>) => Prototype
For common operations, it is preferable to provide a cleaner definition so that users can interact with your API more smoothly. To redefine or create custom operations, we can use prototype.ops.
1 | prototype.ops({ |
Here we redefine the add operation so that it takes two arguments and a callback. Note that we can still use the automatically generated operation. We have redefined add, but _add will remain unaffected.
We also take the opportunity to return only the relevant data to the user (the sum). As a result, clients can use our API much more easily:
1 | client.add(2, 3, function (errs, sum) { |
Initializing a Client
prototype.init: (access: Access, [options]: Map) => Client
prototype.initFromServiceInfo: (access: Access, [options]: Map, callback: Function) => Void
Users can create a client by calling the prototype.init function. This function takes a bal.Access instance to send queries with as well as a set of options:
1 | var client = prototype.init(access, { |
The options passed here will also be available to custom operations through the this.options variable.
It is also possible to initialize a client and populate the operation data by requesting the service info of that service:
1 | prototype.initFromServiceInfo(access, function (errs, client) { |
Changing Default Context
client.withContext: (context: Object) => Client
It is possible to set the default context sent by a client using the withContext
function. This will return a new client object that adds the passed context to every message it sends.
1 | var authorizedClient = client.withContext({ identity: token }); |
This context can be overridden on an individual call basis as well:
1 | authorizedClient.add({}, { id: 2 }, function (errs, results) { /* ... */}); |
Default Operations
Certain common service operations are automatically provided.
client.echo: (callback: Function) => Void
1
2
3
4
5var client = bal.client("avid.acs.calculator", "global", 3).init(access);
client.echo(function (errs, results) {
console.log("Echo response is", results);
});client.serviceInfo: (callback: Function) => Void
1
2
3
4
5var client = bal.client("avid.acs.calculator", "global", 3).init(access);
client.serviceInfo(function (errs, info) {
console.log("Service info is", info);
});client.serviceStatus: (callback: Function) => Void
1
2
3
4
5var client = bal.client("avid.acs.calculator", "global", 3).init(access);
client.serviceStatus(function (errs, status) {
console.log("Service status is", status);
});
Full Calculator Prototype Example
1 | var bal = require('proxy-bal'); |