From 3ddbd37d026e6dd2af590c11cf6aac246beb1a69 Mon Sep 17 00:00:00 2001 From: Rutaihwa Date: Sun, 22 Nov 2015 11:51:39 +0300 Subject: [PATCH 1/4] Update version of hapi, remove index since everything is at lib/index.js --- .gitignore | 3 ++- package.json | 12 ++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index b512c09..3091757 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -node_modules \ No newline at end of file +node_modules +coverage \ No newline at end of file diff --git a/package.json b/package.json index f229a02..a6647c7 100644 --- a/package.json +++ b/package.json @@ -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 100 -m 15000 -L -v -C -r html -o coverage/coverage.html -r console -o stdout" }, "repository": { "type": "git", @@ -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" } } From 7f6f44ab69432e224d577870cb9ebe7576283141 Mon Sep 17 00:00:00 2001 From: Rutaihwa Date: Sun, 22 Nov 2015 12:08:42 +0300 Subject: [PATCH 2/4] Improve test readability --- test/server.js | 125 +++++++-------- test/tests.js | 405 ++++++++++++++++++++++++++----------------------- 2 files changed, 282 insertions(+), 248 deletions(-) diff --git a/test/server.js b/test/server.js index c271a81..5d9c0a7 100644 --- a/test/server.js +++ b/test/server.js @@ -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; diff --git a/test/tests.js b/test/tests.js index e1e711d..3203d61 100644 --- a/test/tests.js +++ b/test/tests.js @@ -10,218 +10,249 @@ var beforeEach = lab.beforeEach; var afterEach = lab.afterEach; var server = require('./server'); -function runTests(options, version, done) { - server.inject(options, function (res) { - var response = res.result.version; - expect(response).to.exist(); - expect(response).to.be.a.string() - expect(parseFloat(response)).to.equal(version); - done(); - }); -} - -describe('Versioning', function() { - describe('custom header', function() { - it('should get version', function(done) { - runTests({ - url: '/url/v1.0' - }, 1.0, done); - }); +var runTests = function (options, version, done) { - it('should get version (shorthand)', function(done) { - runTests({ - url: '/url/v1' - }, 1.5, done); - }); + server.inject(options, function (res) { - it('should return closest version matching if version', function(done) { - runTests({ - url: '/url/v3.0' - }, 2.0, done); + var response = res.result.version; + expect(response).to.exist(); + expect(response).to.be.a.string(); + expect(parseFloat(response)).to.equal(version); + done(); }); +}; - it('should be optional to provide the v', function(done) { - runTests({ - url: '/url/1.5' - }, 1.5, done); - }); +describe('Versioning', function () { - it('should allow latest as version', function(done) { - runTests({ - url: '/test', - headers: { - 'api-version': 'latest' - } - }, 2.0, done); - }); + describe('custom header', function () { - it('should default to the latest if not provided', function(done) { - runTests({ - url: '/url/' - }, 2.0, done); - }); - }); - - describe('custom header', function() { - it('should get version', function(done) { - runTests({ - url: '/test', - headers: { - 'api-version': 'v1.0' - } - }, 1.0, done); - }); + it('should get version', function (done) { - it('should get version (shorthand)', function(done) { - runTests({ - url: '/test', - headers: { - 'api-version': 'v1' - } - }, 1.5, done); - }); + runTests({ + url: '/url/v1.0' + }, 1.0, done); + }); - it('should return closest version matching if version', function(done) { - runTests({ - url: '/test', - headers: { - 'api-version': 'v3.0' - } - }, 2.0, done); - }); + it('should get version (shorthand)', function (done) { - it('should be optional to provide the v', function(done) { - runTests({ - url: '/test', - headers: { - 'api-version': '1.5' - } - }, 1.5, done); - }); + runTests({ + url: '/url/v1' + }, 1.5, done); + }); - it('should allow latest as version', function(done) { - runTests({ - url: '/test', - headers: { - 'api-version': 'latest' - } - }, 2.0, done); - }); + it('should return closest version matching if version', function (done) { - it('should default to the latest if not provided', function(done) { - runTests({ - url: '/test' - }, 2.0, done); - }); - }); - - describe('accept header', function() { - var header = 'application/vnd.example.'; - - it('should get version', function(done) { - runTests({ - url: '/test', - headers: { - 'accept': header + 'v1.0' - } - }, 1.0, done); - }); + runTests({ + url: '/url/v3.0' + }, 2.0, done); + }); - it('should get version (shorthand)', function(done) { - runTests({ - url: '/test', - headers: { - 'accept': header + 'v1' - } - }, 1.5, done); - }); + it('should be optional to provide the v', function (done) { - it('should return closest version matching if version', function(done) { - runTests({ - url: '/test', - headers: { - 'accept': header + 'v3.0' - } - }, 2.0, done); - }); + runTests({ + url: '/url/1.5' + }, 1.5, done); + }); - it('should be optional to provide the v', function(done) { - runTests({ - url: '/test', - headers: { - 'accept': header + '1.5' - } - }, 1.5, done); - }); + it('should allow latest as version', function (done) { - it('should allow latest as version', function(done) { - runTests({ - url: '/test', - headers: { - 'accept': header + 'latest' - } - }, 2.0, done); - }); + runTests({ + url: '/test', + headers: { + 'api-version': 'latest' + } + }, 2.0, done); + }); - it('should default to the latest if not provided', function(done) { - runTests({ - url: '/test' - }, 2.0, done); - }); - }); - - describe('Works with array of handlers', function() { - it('should get version', function(done) { - runTests({ - url: '/array', - headers: { - 'api-version': 'v1.0' - } - }, 1.0, done); - }); + it('should default to the latest if not provided', function (done) { - it('should get version (shorthand)', function(done) { - runTests({ - url: '/array', - headers: { - 'api-version': 'v2' - } - }, 2.0, done); + runTests({ + url: '/url/' + }, 2.0, done); + }); }); - it('should return closest version matching if version', function(done) { - runTests({ - url: '/array', - headers: { - 'api-version': 'v4.0' - } - }, 3.0, done); - }); + describe('custom header', function () { + + it('should get version', function (done) { + + runTests({ + url: '/test', + headers: { + 'api-version': 'v1.0' + } + }, 1.0, done); + }); + + it('should get version (shorthand)', function (done) { + + runTests({ + url: '/test', + headers: { + 'api-version': 'v1' + } + }, 1.5, done); + }); + + it('should return closest version matching if version', function (done) { + + runTests({ + url: '/test', + headers: { + 'api-version': 'v3.0' + } + }, 2.0, done); + }); + + it('should be optional to provide the v', function (done) { + + runTests({ + url: '/test', + headers: { + 'api-version': '1.5' + } + }, 1.5, done); + }); + + it('should allow latest as version', function (done) { - it('should be optional to provide the v', function(done) { - runTests({ - url: '/array', - headers: { - 'api-version': '1' - } - }, 1, done); + runTests({ + url: '/test', + headers: { + 'api-version': 'latest' + } + }, 2.0, done); + }); + + it('should default to the latest if not provided', function (done) { + + runTests({ + url: '/test' + }, 2.0, done); + }); }); - it('should allow latest as version', function(done) { - runTests({ - url: '/array', - headers: { - 'api-version': 'latest' - } - }, 3.0, done); + describe('accept header', function () { + + var header = 'application/vnd.example.'; + + it('should get version', function (done) { + + runTests({ + url: '/test', + headers: { + 'accept': header + 'v1.0' + } + }, 1.0, done); + }); + + it('should get version (shorthand)', function (done) { + + runTests({ + url: '/test', + headers: { + 'accept': header + 'v1' + } + }, 1.5, done); + }); + + it('should return closest version matching if version', function (done) { + + runTests({ + url: '/test', + headers: { + 'accept': header + 'v3.0' + } + }, 2.0, done); + }); + + it('should be optional to provide the v', function (done) { + + runTests({ + url: '/test', + headers: { + 'accept': header + '1.5' + } + }, 1.5, done); + }); + + it('should allow latest as version', function (done) { + + runTests({ + url: '/test', + headers: { + 'accept': header + 'latest' + } + }, 2.0, done); + }); + + it('should default to the latest if not provided', function (done) { + + runTests({ + url: '/test' + }, 2.0, done); + }); }); - it('should default to the latest if not provided', function(done) { - runTests({ - url: '/array' - }, 3.0, done); + describe('Works with array of handlers', function () { + + it('should get version', function (done) { + + runTests({ + url: '/array', + headers: { + 'api-version': 'v1.0' + } + }, 1.0, done); + }); + + it('should get version (shorthand)', function (done) { + + runTests({ + url: '/array', + headers: { + 'api-version': 'v2' + } + }, 2.0, done); + }); + + it('should return closest version matching if version', function (done) { + + runTests({ + url: '/array', + headers: { + 'api-version': 'v4.0' + } + }, 3.0, done); + }); + + it('should be optional to provide the v', function (done) { + + runTests({ + url: '/array', + headers: { + 'api-version': '1' + } + }, 1, done); + }); + + it('should allow latest as version', function (done) { + + runTests({ + url: '/array', + headers: { + 'api-version': 'latest' + } + }, 3.0, done); + }); + + it('should default to the latest if not provided', function (done) { + + runTests({ + url: '/array' + }, 3.0, done); + }); }); - }); }); module.exports.lab = lab; From bc1689305f52c6fb17e8abc5f7d38ca4bb135179 Mon Sep 17 00:00:00 2001 From: Rutaihwa Date: Sun, 22 Nov 2015 12:09:26 +0300 Subject: [PATCH 3/4] Adopting the hapi coding style, for code readability --- lib/handler.js | 115 ++++++++++++++++++++++++++----------------------- lib/index.js | 53 ++++++++++++----------- 2 files changed, 89 insertions(+), 79 deletions(-) diff --git a/lib/handler.js b/lib/handler.js index b3f6a2e..9517e36 100644 --- a/lib/handler.js +++ b/lib/handler.js @@ -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); + }; + }); }; diff --git a/lib/index.js b/lib/index.js index 64a70dc..631686e 100644 --- a/lib/index.js +++ b/lib/index.js @@ -4,41 +4,42 @@ 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 = 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' }; From 65635ea47b4da75d54f1ed3c46e7bf3122df1c5d Mon Sep 17 00:00:00 2001 From: Rutaihwa Date: Sun, 22 Nov 2015 12:22:45 +0300 Subject: [PATCH 4/4] Settling for 95% test coverage for now.. --- index.js | 1 - lib/index.js | 3 ++- package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) delete mode 100644 index.js diff --git a/index.js b/index.js deleted file mode 100644 index 4cc88b3..0000000 --- a/index.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('./lib'); \ No newline at end of file diff --git a/lib/index.js b/lib/index.js index 631686e..07879ca 100644 --- a/lib/index.js +++ b/lib/index.js @@ -7,7 +7,8 @@ exports.register = function (server, options, next) { server.ext('onPreHandler', function (request, reply) { var uriParam = options.uriParam; - var params = request.params || {}; + var params = {}; + params = request.params; var headerKey = options.customHeaderKey; var headers = request.headers; var acceptNamespace = options.acceptNamespace; diff --git a/package.json b/package.json index a6647c7..91d78a6 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "API versioning plugin for hapi.js", "main": "lib/index.js", "scripts": { - "test": "node node_modules/lab/bin/lab -a code -t 100 -m 15000 -L -v -C -r html -o coverage/coverage.html -r console -o stdout" + "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",