multiagent

2.1.0 • Public • Published

multiagent

Simple HTTP client with failover functionality for node.js and browsers

It supports simple fallback addresses as well as dynamic service discovery using Consul.

Multiagent uses superagent under the covers and exposes most of its API as well as an additional promise interface (if native promises are available).

All browsers with ECMAScript 5 support should work.

Installation

node.js, browserify, webpack:

npm install --save multiagent

as a global script in the browser:

<script src="node_modules/multiagent/lib/browser.min.js"></script>

from a CDN:

<script src="https://npmcdn.com/multiagent/lib/browser.min.js"></script>

In case you load multiagent with a script reference into the browser, it will create the global variable multiagent.

Examples

Simple HTTP requests

Multiagent can be used as a simple HTTP client, pretty much as a drop-in replacement of superagent:

const agent = require('multiagent');
 
// create a request:
const req = agent.request('GET', 'http://domain.com');
 
// or use a shorthand (there's also: 'head', 'post', 'put', 'delete'/'del')
const req = agent.get('http://domain.com');
 
// execute a request, providing a callback:
req.end((err, res) => console.log(err || res.body));
 
// or instead, use the promise interface:
const promise = req.promise();
promise.then(res => console.log(res.body), err => console.log(err));
 
// you can also simply just call 'then' (or 'catch') on the request:
req.then(res => console.log(res.body), err => console.log(err));

HTTP client with failover

If you have your service running on multiple endpoints, you can provide a list of hard-coded server URLs and take advantage of multiagent's failover mechanism:

const agent = require('multiagent');
 
// create a client:
const client = agent.client({
  servers: ['http://sub1.abc.com', 'http://sub2.abc.com', 'http://sub3.abc.com']
});
 
// then do stuff:
client
  .get('/endpoint') // use just the path without host!
  .timeout(500) // used per individual call!
  .end((err, res) => console.log(err || res.body));

HTTP client with discovery using Consul

Instead of hard-coding your server URLs you can use a Consul server or cluster to dynamically resolve the base URLs for your service calls:

const agent = require('multiagent');
 
// create a client:
const client = agent.client({
  discovery: 'consul', // only possible value at the moment, more could be added in the future
  discoveryServers: ['http://consul1.abc.com', 'http://consul2.abc.com', 'http://consul3.abc.com'],
  serviceName: 'my-service'
});
 
// then do stuff:
client
  .get('/endpoint') // use just the path without host!
  .timeout(500) // used per individual service call!
  .end((err, res) => console.log(err || res.body));

Getting the server URLs without calling an endpoint

If you're just interested in the service URLs e.g. from Consul without actually calling any service endpoint, you can use the resolveServers function provided by the client instance:

const agent = require('multiagent');
 
// create a client:
const client = agent.client({
  discovery: 'consul',
  discoveryServers: ['http://consul1.abc.com', 'http://consul2.abc.com', 'http://consul3.abc.com'],
  serviceName: 'my-service'
});
 
// get the list of servers providing a callback:
client.resolveServers((err, servers) => console.log(err || servers));
 
// or use the promise interface:
client.resolveServers().then(servers => console.log(servers));

Advanced client options

For the client using simple failover you can pass the following additional options:

  • strategy: string, (sequentially|randomly|simultaneously), default: 'sequentially'
  • shouldFailover: function, default: (err, res) => err || res.status >= 400

For the client using Consul you can pass the following additional options:

  • serviceProtocol: string, (http|https), default: 'http'
  • serviceStrategy: string, (sequentially|randomly|simultaneously), default: 'sequentially'
  • discoveryTimeout: number, in milliseconds, default: 2000
  • discoveryStrategy: string, (sequentially|randomly|simultaneously), default: 'simultaneously'
  • refreshAfter: number, in milliseconds, default: 60000
  • shouldFailover: function, default: (err, res) => err || res.status >= 400
  • createConsulRequestPath: function, default: serviceName => `/v1/health/service/${encodeURIComponent(serviceName)}?passing=true`,
  • createServerListFromConsulResponse: function, default: (body, serviceProtocol) => body.map(x => `${serviceProtocol}://${x.Service.Address}:${x.Service.Port}`)

Finetuning failover options on a per request basis

When you create a client with failover using agent.client({ /* options */ }) you can override the failover strategy as well as the failover criteria on a per request basis. This is sometimes useful when e.g. in a RESTful environment a response with status code 404 (not found) is a perfectly valid result and should not lead to any failover:

// create a client with default options for all requests issued using this client instance:
const client = agent.client({
  servers: ['http://sub1.abc.com', 'http://sub2.abc.com', 'http://sub3.abc.com'],
  strategy: 'simultaneously',
  shouldFailover: (err, res) => err || res.status >= 400
});
 
// this will execute the requests sequentially and NOT failover on a 404 status response,
// thus overriding the options 'strategy' and 'shouldFailover' set as default on the client:
client
  .get('/endpoint')
  .failover({ strategy: 'sequentially' })
  .failover({ shouldFailover: (err, res) => err || (res.status >= 400 && res.status !== 404) }) 

Supported API

The following functions from superagent are supported:

On the client

  • head
  • get
  • post
  • put
  • delete
  • del

Additionally:

  • request
  • resolveServers

On the request

  • set
  • query
  • send
  • type
  • accept
  • timeout
  • auth
  • redirects
  • attach
  • field
  • withCredentials
  • abort
  • end

Additionally:

  • failover
  • promise
  • then
  • catch

License

MIT

Dependencies (2)

Dev Dependencies (25)

Package Sidebar

Install

npm i multiagent

Weekly Downloads

31

Version

2.1.0

License

MIT

Last publish

Collaborators

  • ahelmberger