npm package: @fuzzy-ai/microservice-client
Description: Simple microservice client class used by Fuzzy.ai
Latest version: 1.1.1

fuzzy.ai-microservice-client
============================

This is a useful client library for interacting with certain kinds of
microservices.

In particular, it works well for RESTful services that use JSON for request and
response payloads, and RFC 6750 Bearer Tokens for authorization.

License
-------

Copyright 2016,2018 Fuzzy.ai

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

MicroserviceClient
------------------

The main class is MicroserviceClient, which is also the export from the module.
You can use it directly to access microservices.

```javascript
  var util = require('util');
  var MicroserviceClient = require('fuzzy.ai-microservice-client');

  var options = {
    root: "http://service.example",
    key: "A1B2C3D4E5F6G7",
    queueLength: 32,
    maxWait: 10
  };

  var client = new MicroserviceClient(options);

  client.get("/widget", function(err, widgets) {
      if (err) {
        console.error(err);
      } else {
        console.dir(widgets);
      }
  });
```

You can also use it to inherit for your own client classes.

```javascript
  var util = require('util');
  var MicroserviceClient = require('fuzzy.ai-microservice-client');

  var MyServiceClient = function(options) {
    MicroserviceClient.call(this, options);
  };

  util.inherits(MyServiceClient, MicroserviceClient);

  MyServiceClient.prototype.getAllWidgets = function(callback) {
    this.get("/widget", callback);
  };
```

Constructor
-----------

The constructor takes an `options` object as the only parameter. `options` can
have the following properties.

* **root**: The root of the microservice's URLs. Usually something like
  'https://hostname' or 'http://hostname:port' or 'http://hostname'. Required.
* **key**: The API key for the microservice. This is used to identify your
  client and authorize it for whatever stuff it can do on the microservice.
* **queueLength**: The client will queue up requests to the microservice to avoid
  flooding it with requests. This parameter defines how many requests can go
  into the queue concurrently. Default is 16.
* **maxWait**: If there are errors that look sporadic or related to the server,
  the client will retry the requests. (See "Retries" below.) This parameter
  defines how many seconds you're willing to wait on retries. Default is
  Infinity; the client will retry forever otherwise.
* **cacheSize**: Size of the cache to use. We use an LRU caching library, so
  if there are more GETs than fit in the cache, the oldest ones get kicked. Must
  be a number greater than 0; default is 100.
* **timeout**: For persistent connections, this is how long in ms to keep the
  connections open before closing them. Defaults to 1000 (1 second). If it's
  Infinity, connections never time out. If it's 0, don't use persistent
  connections.
* **webClient** A WebClient instance to use, instead of having the
  MicroserviceClient create its own. This is useful if you want to share
  persistent connections and so on.

Methods
-------

* **get(relative, callback)** GET the resource at `relative`. `callback` takes
  two parameters: an error and the parsed results.
* **post(relative, reqBody, callback)** POST the `reqBody` to `relative`.
  `callback` takes two parameters: an error and the parsed results.
* **put(relative, reqBody, callback)** PUT the `reqBody` to `relative` which
  should replace the contents of that resource. `callback` takes two parameters:
  an error and the parsed results.
* **patch(relative, reqBody, callback)** PATCH the `reqBody` to `relative` which
  should be added the contents of that resource. `callback` takes two
  parameters: an error and the parsed results.
* **delete(relative, callback)** DELETE the resource at `relative`. `callback`
  takes two parameters: an error and the parsed results.
* **stop(callback)** Close all persistent connections. Needed at shutdown if
  you have persistent connections on (otherwise your program won't stop).

Events
------

The client is an (EventEmitter)[https://nodejs.org/api/events.html] so you can
use all the regular event-monitoring methods you expect. It emits the following
events:

* **error** When there is an error with a request. Sometimes these errors are
  passed back to callback functions; other times the system retries. This event
  is mostly useful for logging and debugging.

* **cache-hit** When there is a GET request for an URL that is already in the
  cache. Arguments are `url`, `cacheItem`, where `cacheItem` is a
  `CacheItem` instance as described below. Note that cache hits are not always
  returned directly; only if their `expires` property is in the future.

* **cache-miss** When there is a GET request and the URL is not in the cache.
  Argument is `url`.

* **cache-results** When there is a cache item that has a far-enough future
  `expires` property to return it directly. Arguments are `url` and `cacheItem`.

* **cache-unmodified** When an URL is in the cache, but the `expires` is not
  sufficiently in the future that we can count on it, we continue the request.
  If the request comes back with the 304 Unmodified status, the cache results
  are returned, and this event is fired. Arguments are `url` and `cacheItem`.

* **cache-modified** If the request comes back succesfully but with a different
  status than 304 Unmodified. Arguments are `url` and `cacheItem`.

The `CacheItem` class has the following properties.

* `url`: The URL that was requested.
* `body`: body of the response, as a string.
* `lastModified`: Last-Modified date, in Date number format.
* `expires`: Expires date, in Date number format.
* `etag`: ETag for the response.

Queue
-----

The client tries not to flood a microservice with too many concurrent requests,
by putting them into a queue. If you increase the queue length, it should give
you faster responses, with corresponding higher load on the microservice.

Retries
-------

If there are errors that seem to be recoverable, the client will retry the
request after waiting a variable amount of time. It uses a truncated
[exponential backoff](https://en.wikipedia.org/wiki/Exponential_backoff)
algorithm to avoid congestion.

If you need to have results in a fixed amount of time (for example, for
interactive code), set the `maxWait` for the client. Note that the maxWait
parameter works for all the methods.

Cache
-----

Results of GET requests are saved in an LRU (least-recently-used) cache within
the client. There are several events (see above) for getting finer information
on the cache performance.

To benefit from caching, there are a few things worth doing:

* Add a Last-Modified header for resources where you know when they were last
  modified.
* Add an Expires header for resources where you know when they will expire.
* For resources that are immutable (never change) set the
  Expires header to the far future, e.g. 10 years from last modification.

Persistent connections
----------------------

The class will use persistent connections if you set the `timeout` option to
something non-zero (it's 1000 by default, so persistent connections are on by
default). To clean up any persistent connections before exiting, run the
`stop()` method.