Instantly share code, notes, and snippets.

Embed
What would you like to do?
A simple REST implementation of Azure DocumentDB with help of Total.js framework
const Crypto = require('crypto');
require('total.js');
function DocumentDB(hostname, key) {
this.hostname = hostname;
this.key = key;
this.attempts = 0;
this.expiration = '10 minutes';
}
global.DocumentDB = DocumentDB;
DocumentDB.DOCUMENTDB = {};
DocumentDB.prototype.createToken = function(method, type, id, recreate) {
var keycache = ((this.hostname || '') + (method || '') + (type || '') + (id || '')).hash().toString();
var meta = DocumentDB.DOCUMENTDB[keycache];
var date = new Date();
if (meta && !recreate) {
if (meta.expire > new Date().add('-' + this.expiration).getTime())
return meta;
}
var key = new Buffer(this.key, 'base64');
var builder = [];
builder.push((method || '').toLowerCase());
builder.push((type || '').toLowerCase());
builder.push(id || '');
builder.push(date.toUTCString().toLowerCase());
builder.push('');
var body = new Buffer(builder.join('\n') + '\n', 'utf8');
return DocumentDB.DOCUMENTDB[keycache] = { token: 'type=master&ver=1.0&sig=' + Crypto.createHmac('sha256', key).update(body).digest('base64'), utc: date.toUTCString(), expire: date.getTime() };
};
DocumentDB.prototype.createBuilder = function(method, type, id, recreate) {
var builder = new RESTBuilder();
var meta = this.createToken(method, type, id, recreate);
builder.header('x-ms-date', meta.utc);
builder.header('x-ms-version', '2015-08-06');
builder.header('authorization', meta.token);
builder.header('cache-control', 'no-cache');
builder.noDnsCache();
builder.timeout(0);
builder.method(method);
return builder;
};
DocumentDB.prototype.callback = function(err, response, callback) {
if (response.code === 'Unauthorized') {
if (this.attempts++ > 30) {
callback && callback(err, response);
return true;
}
return false;
}
this.attempts = 0;
callback && callback(err, response);
return true;
};
DocumentDB.prototype.insert = function(database, collection, doc, callback, recreate) {
var self = this;
var builder = this.createBuilder('POST', 'docs', 'dbs/{0}/colls/{1}'.format(database, collection), recreate);
builder.header('x-ms-documentdb-isquery', true);
builder.url(this.hostname + '/dbs/{0}/colls/{1}/docs'.format(database, collection));
builder.json(doc);
builder.exec((err, response) => !self.callback(err, response, callback) && self.insert(database, collection, doc, callback, true));
};
DocumentDB.prototype.query = function(database, collection, query, callback, recreate) {
var self = this;
var builder = self.createBuilder('POST', 'docs', 'dbs/{0}/colls/{1}'.format(database, collection), recreate);
builder.header('x-ms-documentdb-isquery', true);
builder.header('content-type', 'application/query+json');
builder.url(self.hostname + '/dbs/{0}/colls/{1}/docs'.format(database, collection));
builder.json({ query: query });
builder.exec((err, response) => !self.callback(err, response, callback) && self.query(database, collection, query, callback, true));
};
DocumentDB.prototype.databases = function(callback, recreate) {
var self = this;
var builder = this.createBuilder('GET', 'dbs', '', recreate);
builder.url(this.hostname + '/dbs');
builder.exec((err, response) => !self.callback(err, response, callback) && self.databases(callback, true));
};
// USAGE:
// "DocumentDB" is a global variable
var db = new DocumentDB('https://yourDB.documents.azure.com', 'YOUR_MASTER_KEY');
// db.query(database, collection, query, callback);
// db.insert(database, collection, doc, callback);
// db.databases(callback);
db.query('sensors', 'items', 'SELECT TOP 10 * FROM root', (err, json) => console.log(json));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment