Home

Awesome

Kansas API Documentation

Token based rate limited API to go!

Related Packages

<a name='TOC'>Table of Contents</a>

  1. Configuration
  2. Database Connection
  3. Policies 1. Creating Policies 1. Reading Policies 1. Checking Policies 1. Change Owner's Policy 1. The Policy Item
  4. Tokens 1. Creating Tokens Create a token item. 1. Fetching Tokens Get a token item. 1. Deleting Tokens Delete a token item. 1. Consuming Tokens Decrease units from a defined limit. 1. Counting Tokens Add units starting from 1. 1. Fetch By Owner Id Get all token items for the provided owner id. 1. Get Token Usage Get the usage items of a token for the current period. 1. Get Usage by Owner Get all the token items including usage items for the current period. 1. The Token Item A break out of the token item data object.
  5. Kansas Middleware
  6. Kansas Events
  7. Kansas Errors 1. Kansas BaseError 1. Kansas Database 1. Kansas Validation 1. Kansas TokenNotExists 1. Kansas UsageLimit 1. How to work with Errors
  8. Database Maintenance 1. Prepopulating Usage Keys 1. Nuke the Database

<a name='configuration'>Configuration</a>

Kansas can be configured at instantiation or by using the setup() method.

var kansas = require('kansas');

exports.kansas = kansas({/* options */});

// this will work too
exports.kansas.setup({/* options */});

NOTICE Logging options cannot be set using the setup() method. They can only be set during instantiation.

Available Options

Example

var kansas = require('kansas');

exports.kansas = kansas({
    // don't log to console
    console: false,
});

exports.kansas.setup({
    port: 7777,
    host: 'some.redis.host.com',
    password: 'secret',
});

[⬆]

<a name='connect'>Connecting to Redis</a>

kansas.connect() No arguments.

Returns Promise A Promise.

Before you start a connection Kansas will refuse to perform any task. Connecting to Redis is a plain Promise returning method, connect().

var kansas = require('kansas');

exports.kansas = kansas();

exports.kansas.connect()
  .then(function() {
    console.log('Connected!');
  }).catch(function(err){
    console.error('Opts, something went wrong:', err);
  });

[⬆]

<a name='policies'>Policies</a>

Policies are stored in memory. After many iterations it became apparent that this is the most efficient way to work with policies. You define and maintain them inside your application, they are shared between multiple cores and stored in memory, saving on needless database reads.

<a name='policies-creating'>Creating policies</a>

kansas.policy.create(options)

Returns Object The Policy Item.

There are two types of policies that you can create, the Consume Policy and the Count Policy.

The Consume Policy Type

The consuming policies have a finite number of total API calls that can be made within the given period. Each API call consumes one unit from this pool. When all units have been consumed Kansas will deny access to the resource.

To create a Consume Policy you need to define the following parameters:

kansas.policy.create({
  name: 'free',
  maxTokens: 3, // max tokens per owner
  limit: 100 // max usage units per period
});

The Count Policy Type

The counting policies have no limit to usage, their only purpose is to count how many API calls where performed. Each new period starts the API usage counter from 0 (zero).

To create a counting policy you just need to turn the count switch on and omit the limit attribute:

kansas.policy.create({
  name: 'enterprise',
  maxTokens: 10,
  count: true,
});

[⬆]

<a name='policies-read'>Reading a Policy</a>

kansas.policy.get(policyName)

Returns Object The Policy Item.

var policyItem = kansas.policy.get('free');

[⬆]

<a name='policies-has'>Checking a Policy exists</a>

kansas.policy.has(policyName)

Returns boolean Yes or no.

var policyExists = kansas.policy.has('free');

[⬆]

<a name='policies-change'>Change an Owner's policy</a>

kansas.policy.change(options)

Returns Promise A promise.

You'll typically use this when an owner upgrades or downgrades to a new plan. Beware, the usage units will reset to the Policy's limits.

kansas.policy.change({
  ownerId: 'a-unique-id'
  policyName: 'basic',
})
  .then(function() {
    console.log('It Worked!');
  }).catch(function(err) {
    console.error('Uhhhhh duh?', err);
  });

[⬆]

<a name='policies-item'>The Policy Item</a>

When a policy item is returned from Kansas, this is the structure it will have:

var policyItem = {
  /** @type {string} The policy's name */
  name: 'free',
  /** @type {number} Maximum tokens per owner */
  maxTokens: 3,
  /** @type {number=} Maximum usage units per period */
  limit: 10,
  /** @type {boolean=} Make this a Count Policy */
  count: false,
  /** @type {kansas.model.PeriodBucket.Period} Period's enum */
  period: 'month',
};

[⬆]

<a name='tokens'>Tokens</a>

<a name='creating-tokens'>Creating Tokens</a>

kansas.create(options)

kansas.create is an alias to kansas.set

Returns Promise(tokenItem) A promise returning the tokenItem an Object.

Creates a token and populates usage keys and indexes.

kansas.create({
  ownerId: 'a-unique-id'
  policyName: 'basic',
})
  .then(function(tokenItem) {
    console.log('It Worked!', tokenItem);
    console.log('Here is the token:', tokenItem.token);
  }).catch(function(err) {
    console.error('OH NO!', err);
  });

This method has Before / After Middleware.

[⬆]

<a name='get-tokens'>Fetching Tokens</a>

kansas.get(token)

Will fetch a token.

kansas.get('unique-token-id')
  .then(function(tokenItem) {
    console.log('It Worked!', tokenItem);
    console.log('Here is the token:', tokenItem.token);
  }).catch(function(err) {
    console.error('OH NO!', err);
  });

This method has Before / After Middleware.

[⬆]

<a name='del-tokens'>Deleting Tokens</a>

kansas.del(token)

Will delete a token.

kansas.del('unique-token-id')
  .then(function() {
    console.log('Token Deleted!');
  }).catch(function(err) {
    console.error('OH NO!', err);
  });

This method has Before / After Middleware.

[⬆]

<a name='count-tokens'>Adding up Tokens</a>

kansas.count(token, optUnits)

Will add up a consume unit and return how many units were used.

[⬆]

<a name='consuming-tokens'>Consuming Tokens</a>

kansas.consume(token, optUnits)

Will consume a unit and return the remaining units.

kansas.consume('token')
  .then(function(remaining) {
    console.log('Units remaining:', remaining);
  }).catch(function(err) {
    console.error('No more units!', err);
  });

// consume multiple units
kansas.consume('token', 5)
  .then(function(remaining) {
    console.log('Units remaining:', remaining);
  }).catch(function(err) {
    console.error('No more units!', err);
  });

This method has Before / After Middleware.

[⬆]

<a name='getByOwnerId-tokens'>Fetch Tokens By Owner Id</a>

kansas.getByOwnerId(ownerId)

Returns Promise(Array.<Object>) A promise with an array of tokenItems.

Will fetch all tokens based on Owner Id.

kansas.getByOwnerId('hip')
  .then(function(tokens) {
    console.log('Total Tokens:', tokens.length);
  }).catch(function(err) {
    console.error('OH NO!', err);
  });

This method has Before / After Middleware.

[⬆]

<a name='getUsage'>Get Token Usage</a>

kansas.getUsage(tokenId, optTokenItem)

Returns Promise(number) A promise with a number representing the units consumed for the given token.

Get the usage items of a token for the current period.

[⬆]

<a name='tokens-item'>The Token Item</a>

When a Token item is returned from Kansas, this is the structure it will have:

var tokenItem = {
  /** @type {string} The token */
  token: 'random-32-char-string',
  /** @type {string} The Policy's name this token belogs to */
  policyName: 'free',
  /** @type {number} The usage limit per period */
  limit: 10;
  /** @type {boolean} Indicates the token is a 'count' type */
  count: false;
  /** @type {kansas.model.PeriodBucket.Period} The period */
  period: 'month';
  /** @type {string} Any string uniquely identifying the owner */
  ownerId: 'hip';
  /** @type {string} An ISO 8601 formated date */
  createdOn: '2014-03-01T18:12:15.711Z';

  /** @type {number}  How many units were consumed in this perdiod */
  // This attribute is only available if the item is of type 'count'
  consumed: 10,

  /** @type {number}  How many units remain in this perdiod */
  // This attribute is only available if the item is of type 'limit'
  remaining: 10,
};

[⬆]

<a name='middleware'>Kansas Middleware</a>

Kansas uses the Middlewarify package to apply the middleware pattern to its methods. More specifically the Before/After type of middleware has been applied to the following methods:

Each of these methods has the Before/After methods so you can add corresponding middleware. All middleware get the same arguments, all After middleware receive an extra argument which is the result of the main middleware resolution.

kansas.set.before(function(params) {
  console.log(params.ownerId); // prints 'hip'
});

kansas.set.after(function(params, tokenItem) {
  console.log(tokenItem.token); // the generated token
});

kansas.create({
  ownerId: 'hip',
  policyName: 'free',
});

To pass control asynchronously from a middleware you need to return a Promise:

kansas.set.before(function(params) {
  return new Promise(function(resolve, reject) {
    performAsyncFunction(function(err) {
        if (err) { return reject(err); }

        // pass control
        resolve();
    });
  });
});

[⬆]

<a name='events'>Kansas Events</a>

You can hook for emitted events using the on() method. Kansas will emmit the following type of events:

How to hook on events

kansas.on('consume', function(token, consumed, remaining) {
  console.log('Token:', token, ' Consumed:',
    consumed, 'Remaining units:', remaining);
});

<a name='errors'>Kansas Errors</a>

Kansas signs all error Objects so you have a better chance of determining what went wrong. All error Constructors are exposed through the kansas.error namespace.

<a name='errors-BaseError'>kansas.error.BaseError</a>

All Kansas errors inherit from this Class. BaseError provides these properties:

[⬆]

<a name='errors-Database'>kansas.error.Database</a>

Errors related to the Redis Database. Provides the following properties

[⬆]

<a name='errors-Validation'>kansas.error.Validation</a>

Validation errors. Provides the following properties

[⬆]

<a name='errors-TokenNotExists'>kansas.error.TokenNotExists</a>

Token does not exist error. Provides the following properties

[⬆]

<a name='errors-UsageLimit'>kansas.error.UsageLimit</a>

Usage limits errors. Provides the following properties

[⬆]

<a name='errors-howtowork'>How to work with Errors</a>

Use Javascript's instanceof to determine the type of error you received.

kansas.consume('unique-token-id')
  .then(onsuccess)
  .catch(function(err) {
    if (err instanceof kansas.error.TokenNotExists) {
      console.log('This token does not exist');
    }
    if (err instanceof kansas.error.UsageLimit) {
      console.log('Usage limit reached!');
    }
  });

[⬆]

<a name='logger'>Kansas Logging Facilities</a>

Kansas uses the node-logg package to perform logging. The following logging behavior can only be defined during instatiation:

var logg = require('logg');
var kansas = require('kansas');

exports.kansas = kansas({
    logging: true,
    console: false,
    logg: logg,
    level: 100,
});

[⬆]

<a name='logger-events'>Logging Events</a>

All logging messages are emitted as events from kansas. The namespace to listen for is message:

kansas.on('message', function(logObj) {
    console.log('Log:', logObj);
});

Here is a sample logObj:

var logObj = {
  level: 100,
  name: 'cc.model.Token',
  rawArgs: [ 'createActual() :: Init...' ],
  date: 'Tue Apr 16 2013 18:29:52 GMT+0300 (EEST)',
  message: 'createActual() :: Init...',
};

[⬆]

<a name='maintenance'>Database Maintenance</a>

The following Database maintenance tasks are available under the db namespace.

[⬆]

<a name='maintenance-prepopulate'>Prepopulate Usage Keys</a>

TL;DR You need to run the kansas.db.prepopulate() method once per month to populate the next month's usage keys.

Consuming units is the most repeatedly invoked method of Kansas, thus certain performance restrictions apply. In order to have blazing fast speeds the Consume operation has been reduced to a single database call, DECR.

In order for this to happen Kansas creates new keys with the limit as value. i.e. a Kansas usage key can be:

kansas:usage:2014-02-01:token-unique-id = 10

That way Kansas can calculate the key to perform the DECR op given the token and the current date.

Each time a token is created Kansas will populate the usage keys for the current period (month) and the next period (month). By design there is no built-in way to prepopulate the usage keys with each passing month. This operation can potentially be very costly and you should have the responsibility and control of when and where it's run.

kansas.db.prepopulate()

Returns Promise() A promise.

Run once each month to populate the usage keys for the next month.

The db.prepopulate() method is safe to run multiple times, the effect will be to overwrite any existing next months records. They haven't been consumed so the operation has no effect to your accounting.

kansas.db.prepopulate().then(function() {
  console.log('Done!');
}).catch(function(err) {
  console.error('An error occurred', err);
});

[⬆]

<a name='maintenance-nuke'>Nuke the Database</a>

WARNING Irreversible purging of all data WARNING

That said, here's how to nuke the db for your testing purposes:

kansas.db.nuke(confirm, confirmPrefix)

Returns Promise() A promise.

The confirmation string is Yes purge all records irreversibly

var kansas = kansas({prefix: 'test'});

kansas.db.nuke('Yes purge all records irreversibly', 'test').then(function() {
  console.log('Poof Gone!');
}).catch(function(err) {
  console.error('An error occurred', err);
});

[⬆]