Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
node_modules
node_modules
coverage
1 change: 0 additions & 1 deletion index.js

This file was deleted.

115 changes: 62 additions & 53 deletions lib/handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,77 +3,86 @@
var _ = require('lodash');
var cache = {};

function versionToFloat(v, noShorthand) {
if (_.isString(v)) {
v = v.replace('v', '');
var versionToFloat = function (v, noShorthand) {

if (! noShorthand && v.length == 1) {
v = v + '.99';
if (_.isString(v)) {
v = v.replace('v', '');

if (!noShorthand && v.length === 1) {
v = v + '.99';
}
}
}

return parseFloat(v);
}
return parseFloat(v);
};

function cachedVersion(id, version) {
return cache[id] && cache[id][version];
}
var cachedVersion = function (id, version) {

function detectVersionHandler(id, version, handlers) {
var handler;
var versions = Object.keys(handlers).sort()
.reverse();
return cache[id] && cache[id][version];
};

_.some(versions, function testVersion(v) {
if (v <= version) {
handler = handlers[v];
}
var detectVersionHandler = function (id, version, handlers) {

var handler;
var versions = Object.keys(handlers).sort()
.reverse();

_.some(versions, function testVersion (v) {

if (v <= version) {
handler = handlers[v];
}

return handler;
});

cacheVersionHandler(id, version, handler);

return handler;
});
};

cacheVersionHandler(id, version, handler);
var cacheVersionHandler = function (id, version, handler) {

return handler;
}
if (id) {
cache[id] = cache[id] || {};
cache[id][version] = handler;
}
};

function cacheVersionHandler(id, version, handler) {
if (id) {
cache[id] = cache[id] || {};
cache[id][version] = handler;
}
}
module.exports = function register (server) {

module.exports = function register(server) {
server.handler('versioned', function(route, handlers) {
var id = route.method + '::' + route.path;
var handlersIsArray = _.isArray(handlers);
var versions = {};
server.handler('versioned', function (route, handlers) {

_.each(handlers, function(handler, version) {
version = versionToFloat(version, true);
var id = route.method + '::' + route.path;
var handlersIsArray = _.isArray(handlers);
var versions = {};

if (handlersIsArray) {
version += 1;
}
_.each(handlers, function (handler, version) {

versions[version] = handler;
});
version = versionToFloat(version, true);

var latest = Object.keys(versions).sort().pop();
if (handlersIsArray) {
version += 1;
}

versions.latest = versions[latest];
versions[version] = handler;
});

return function(request, reply) {
var input = request.plugins.consistency.apiVersion;
var version = input !== 'latest' ? versionToFloat(input) : latest;
var handler = cachedVersion(id, version);
var latest = Object.keys(versions).sort().pop();

if (! handler) {
handler = detectVersionHandler(id, version, versions)
}
versions.latest = versions[latest];

return handler(request, reply);
};
});
return function (request, reply) {

var input = request.plugins.consistency.apiVersion;
var version = input !== 'latest' ? versionToFloat(input) : latest;
var handler = cachedVersion(id, version);

if (!handler) {
handler = detectVersionHandler(id, version, versions);
}

return handler(request, reply);
};
});
};
54 changes: 28 additions & 26 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,41 +4,43 @@ var handler = require('./handler');

exports.register = function (server, options, next) {

server.ext('onPreHandler', function (request, reply) {
var uriParam = options.uriParam;
var params = request.params || {};
var headerKey = options.customHeaderKey;
var headers = request.headers;
var acceptNamespace = options.acceptNamespace;
var acceptPattern = new RegExp('^application\/vnd\.' + acceptNamespace + '\.');
var version;
server.ext('onPreHandler', function (request, reply) {

request.plugins.consistency = {};
var uriParam = options.uriParam;
var params = {};
params = request.params;
var headerKey = options.customHeaderKey;
var headers = request.headers;
var acceptNamespace = options.acceptNamespace;
var acceptPattern = new RegExp('^application\/vnd\.' + acceptNamespace + '\.');
var version;

// URI versioning, if enabled
if (uriParam && params[uriParam]) {
version = params[uriParam];
} else if (headerKey && headers[headerKey]) {
version = headers[headerKey];
} else if (acceptNamespace && headers['accept'] && acceptPattern.test(headers['accept'])) {
version = headers['accept'].replace('application/vnd.' + acceptNamespace + '.', '');
} else {
version = 'latest';
}
request.plugins.consistency = {};

// Default to latest
request.plugins.consistency.apiVersion = version;
// URI versioning, if enabled
if (uriParam && params[uriParam]) {
version = params[uriParam];
} else if (headerKey && headers[headerKey]) {
version = headers[headerKey];
} else if (acceptNamespace && headers.accept && acceptPattern.test(headers.accept)) {
version = headers.accept.replace('application/vnd.' + acceptNamespace + '.', '');
} else {
version = 'latest';
}

return reply.continue();
// Default to latest
request.plugins.consistency.apiVersion = version;

});
return reply.continue();

handler(server, options);
});

next();
handler(server, options);

next();

};

exports.register.attributes = {
pkg: require('../package.json')
name: 'zension'
};
12 changes: 6 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
"name": "consistency",
"version": "1.0.0",
"description": "API versioning plugin for hapi.js",
"main": "index.js",
"main": "lib/index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
"test": "node node_modules/lab/bin/lab -a code -t 95 -m 15000 -L -v -C -r html -o coverage/coverage.html -r console -o stdout"
},
"repository": {
"type": "git",
Expand All @@ -22,11 +22,11 @@
},
"homepage": "https://github.com/shakefon/consistency",
"dependencies": {
"lodash": "^3.5.0"
"lodash": "3.x.x"
},
"devDependencies": {
"code": "^1.3.0",
"hapi": "^8.4.0",
"lab": "^5.5.0"
"code": "1.x.x",
"hapi": "10.x.x",
"lab": "5.x.x"
}
}
125 changes: 64 additions & 61 deletions test/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,79 +3,82 @@ var consistency = require('../lib');
var server = new Hapi.Server();


function reply(obj) {
return function(req, rep) {
rep(obj);
}
}
var reply = function (obj) {

return function (req, rep) {

rep(obj);
};
};

server.connection({ port: 3000 });

server.register({
register: consistency,
options: {
uriParam: 'apiVersion',
acceptNamespace: 'example',
customHeaderKey: 'api-version'
}
}, function registerRoutes() {
server.route({
method: 'GET',
path: '/array',
handler: {
versioned: [
reply({
version: '1.0'
}),
reply({
version: '2.0'
}),
reply({
version: '3.0'
})
]
}
});
register: consistency,
options: {
uriParam: 'apiVersion',
acceptNamespace: 'example',
customHeaderKey: 'api-version'
}
}, function registerRoutes () {

server.route({
method: 'GET',
path: '/array',
handler: {
versioned: [
reply({
version: '1.0'
}),
reply({
version: '2.0'
}),
reply({
version: '3.0'
})
]
}
});

server.route({
method: 'GET',
path: '/test',
handler: {
versioned: {
'v1': reply({
version: '1.0'
}),
server.route({
method: 'GET',
path: '/test',
handler: {
versioned: {
'v1': reply({
version: '1.0'
}),

'v2.0': reply({
version: '2.0'
}),
'v2.0': reply({
version: '2.0'
}),

'v1.5': reply({
version: '1.5'
})
'v1.5': reply({
version: '1.5'
})
}
}
}
});
});

server.route({
method: 'GET',
path: '/url/{apiVersion?}',
handler: {
versioned: {
'v1.0': reply({
version: '1.0'
}),
server.route({
method: 'GET',
path: '/url/{apiVersion?}',
handler: {
versioned: {
'v1.0': reply({
version: '1.0'
}),

'v2.0': reply({
version: '2.0'
}),
'v2.0': reply({
version: '2.0'
}),

'v1.5': reply({
version: '1.5'
})
'v1.5': reply({
version: '1.5'
})
}
}
}
});
});
});

module.exports = server;
Loading