multiagent
v2.1.0
Published
Simple HTTP client with failover functionality for node.js and browsers
Downloads
8
Maintainers
Readme
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