Comparing version 1.3.0 to 2.0.0
30
api.js
@@ -21,6 +21,5 @@ module.exports = createApi | ||
/* | ||
* API constructor. Instantiates an empty list of plugins. | ||
* API constructor. | ||
*/ | ||
function Api(options) { | ||
this._plugins = [] | ||
this._options = extend({}, defaults, options) | ||
@@ -39,27 +38,6 @@ | ||
/* | ||
* Add one or many API plugins. | ||
* Create and return the server. | ||
*/ | ||
Api.prototype.plugins = function (path) { | ||
if (!Array.isArray(path)) path = [ path ] | ||
this._plugins = this._plugins.concat(path) | ||
return this | ||
Api.prototype.initialize = function () { | ||
return createServer(this._options) | ||
} | ||
// Alias plugin/plugins | ||
Api.prototype.plugin = Api.prototype.plugins | ||
/* | ||
* Create the server, initialize all of the plugins | ||
* and return the server. | ||
*/ | ||
Api.prototype.initialize = function (serviceLocator, cb) { | ||
var server = createServer(this._options) | ||
try { | ||
this._plugins.forEach(function (plugin) { | ||
plugin(serviceLocator, server) | ||
}) | ||
cb(null, server) | ||
} catch (e) { | ||
cb(e) | ||
} | ||
} |
@@ -10,3 +10,3 @@ module.exports = acceptMiddleware | ||
// If no 'Accept: x' header then bye | ||
if (!req.headers.accept) return res.send(406) | ||
if (!req.headers.accept) return res.status(406).end() | ||
@@ -24,3 +24,3 @@ // Get the list of acceptable response types | ||
&& (accepts.indexOf('application/*') === -1) | ||
&& (accepts.indexOf('*/*') === -1) ) return res.send(406) | ||
&& (accepts.indexOf('*/*') === -1) ) return res.status(406).end() | ||
@@ -27,0 +27,0 @@ // Otherwise hello! |
@@ -17,3 +17,3 @@ module.exports = createCorsMiddleware | ||
if (!allowed) return res.send(403) | ||
if (!allowed) return res.status(403).end() | ||
@@ -23,3 +23,3 @@ // Request came from allowed domain so set acces control headers | ||
{ 'Access-Control-Allow-Origin': req.headers.origin | ||
, 'Access-Control-Allow-Headers': 'Authorization, Content-Type, x-cf-date, *' | ||
, 'Access-Control-Allow-Headers': 'Authorization, Content-Type, x-cf-date, x-cf-ttl, *' | ||
, 'Access-Control-Request-Headers': '*' | ||
@@ -26,0 +26,0 @@ , 'Access-Control-Allow-Methods': 'GET, POST, OPTIONS, PUT, DELETE, PATCH' |
module.exports = createMiddleware | ||
var express = require('express') | ||
var morgan = require('morgan') | ||
@@ -10,12 +10,3 @@ /* | ||
function createMiddleware(logger) { | ||
return express.logger( | ||
{ format: 'short' | ||
, stream: | ||
{ write: function (data) { | ||
logger.info((data + '').trim()) | ||
} | ||
} | ||
}) | ||
} | ||
return morgan('short', { stream: { write: function (data) { logger.info((data + '').trim()) } } }) | ||
} |
@@ -5,3 +5,3 @@ { | ||
"description": "A pluggable JSON API server", | ||
"version": "1.3.0", | ||
"version": "2.0.0", | ||
"tags": [], | ||
@@ -17,5 +17,8 @@ "repository": { | ||
"dependencies": { | ||
"express": "^3.18.2", | ||
"body-parser": "^1.14.1", | ||
"express": "^4.13.3", | ||
"lodash.assign": "^2.4.1", | ||
"lodash.pick": "^2.4.1" | ||
"lodash.pick": "^2.4.1", | ||
"morgan": "^1.6.1", | ||
"response-time": "^2.3.1" | ||
}, | ||
@@ -22,0 +25,0 @@ "devDependencies": { |
@@ -15,23 +15,15 @@ # cf-api | ||
```js | ||
var serviceLocator = require('service-locator').createServiceLocator() | ||
, api = require('cf-api') | ||
var createApi = require('cf-api') | ||
// Register your services on the serviceLocator here… | ||
var api = createApi(options) | ||
server = api.initialize() | ||
api(options) | ||
.plugins([ require('./path/to/plugin'), require('./path/to/other/plugin') ]) | ||
.initialize(serviceLocator, function (err, server) { | ||
if (err) throw err | ||
server.listen(1337) | ||
}) | ||
``` | ||
server.get('/', homepage) | ||
server.post('/form', submit) | ||
A plugin is just a node module with a single synchronous function exported: | ||
// This tells the api that you've finised adding your routes | ||
// and you now want it to add the error handling middleware | ||
server.emit('preBoot') | ||
```js | ||
module.exports = init | ||
function init(serviceLocator, router) { | ||
// Do plugin things… | ||
} | ||
server.listen(port) | ||
``` | ||
@@ -50,25 +42,12 @@ | ||
### api.plugins(Array: plugins) or api.plugin(Function: plugin) | ||
### api.initialize() | ||
Register a list of plugins (or a single plugin). These are not run when they are registered, but when `initialize()` | ||
is called. | ||
Create and return the server. | ||
Returns `api` for chaining. | ||
## Changelog | ||
### api.initialize(Object: serviceLocator, Function: cb) | ||
### 2.0.0 | ||
- Plugin interface now totally removed. Application components are registered outside of the scope of this module. | ||
- User must call `server.emit('preBoot')` after all routes have been added to make tell the api to add the last piece of middleware: the error handler. This is due to a change in Express 4. | ||
Create the server, initialize all of the plugins and callback with the server. Plugin initialize | ||
functions are called with the following arguments: `plugin(serviceLocator, router)`. | ||
Plugins are initialized in the order that they were passed to `plugin()`. | ||
`serviceLocator` is a place where your plugins can speak to application level services. | ||
It could be a plain JS object, but it's better to use something like | ||
[serby/service-locator](https://github.com/serby/service-locator) to prevent naming clashes. | ||
`cb(err, server)` is called when all plugins have been initialized (`err=null`), or on the first | ||
error (`err!=null`). | ||
## Changelog | ||
### 1.1.0 | ||
@@ -75,0 +54,0 @@ - API now allows binary request bodies as well as json |
@@ -12,2 +12,4 @@ module.exports = createServer | ||
, noCache = require('./middleware/no-cache') | ||
, responseTime = require('response-time') | ||
, bodyParser = require('body-parser') | ||
@@ -36,3 +38,3 @@ function createServer(options) { | ||
// X-Response-time: Nms | ||
.use(express.responseTime()) | ||
.use(responseTime()) | ||
@@ -43,3 +45,3 @@ // Whitelist cross domain requests | ||
// Body parse API for JSON content type | ||
.use(express.json()) | ||
.use(bodyParser.json()) | ||
@@ -53,5 +55,2 @@ // Server only speaks JSON | ||
// Be explicit about where in the stack routes handlers are positioned | ||
.use(app.router) | ||
// Handle and log server error | ||
@@ -58,0 +57,0 @@ .use(errorHandler(options.logger)) |
var assert = require('assert') | ||
, api = require('../') | ||
, noopLogger = { debug: noop, info: noop, warn: noop, error: noop } | ||
function noop() {} | ||
describe('api', function () { | ||
@@ -15,6 +12,8 @@ | ||
it('should create an object that has a _plugins array', function () { | ||
assert(Array.isArray(api()._plugins)) | ||
}) | ||
describe('initialize()', function () { | ||
it('should return a server', function () { | ||
assert.equal(typeof api().initialize(), 'function') | ||
}) | ||
}) | ||
@@ -55,68 +54,2 @@ | ||
describe('plugins()', function () { | ||
it('should populate and add to the plugins array', function () { | ||
function noop() {} | ||
var myApi = api() | ||
.plugins([ noop, noop, noop ]) | ||
assert.equal(3, myApi._plugins.length) | ||
myApi.plugins([ noop, noop ]) | ||
assert.equal(5, myApi._plugins.length) | ||
myApi.plugins(noop) | ||
assert.equal(6, myApi._plugins.length) | ||
}) | ||
}) | ||
describe('initialize()', function () { | ||
it('should run all of the functions added with .plugins() in series', function (done) { | ||
var initialized = 0 | ||
function plugin(n) { | ||
return function () { | ||
assert.equal(n, ++initialized) | ||
} | ||
} | ||
api() | ||
.plugins([ plugin(1), plugin(2), plugin(3) ]) | ||
.initialize({ properties: { allowedDomains: [] }, logger: noopLogger }, function (err) { | ||
assert(!err) | ||
assert.equal(3, initialized) | ||
done() | ||
}) | ||
}) | ||
it('should stop on the first error', function (done) { | ||
function run() { | ||
throw new Error('Startup error') | ||
} | ||
function notRun() { | ||
assert(false, 'this plugin function should not be called') | ||
} | ||
api() | ||
.plugins([ run, notRun, notRun ]) | ||
.initialize({ properties: { allowedDomains: [] }, logger: noopLogger }, function (err) { | ||
assert(err) | ||
assert.equal('Startup error', err.message) | ||
done() | ||
}) | ||
}) | ||
}) | ||
}) |
@@ -13,3 +13,3 @@ var request = require('supertest') | ||
app.get('/', function (req, res) { | ||
res.send(200) | ||
res.status(200).end() | ||
}) | ||
@@ -16,0 +16,0 @@ }) |
var assert = require('assert') | ||
, middleware = require('../../../middleware/accepts') | ||
function noop() {} | ||
describe('middleware/accepts unit tests', function () { | ||
it('should send a 406 response to a request with no "Accept"', function (done) { | ||
function mockSend(statusCode) { | ||
assert.equal(statusCode, 406) | ||
function mockStatus(statusCode) { | ||
assert.equal(406, statusCode) | ||
done() | ||
return { end: noop } | ||
} | ||
middleware({ headers: {} }, { send: mockSend }) | ||
middleware({ headers: {} }, { status: mockStatus }) | ||
}) | ||
it('should send a 406 response to a request without json in "Accept" header', function (done) { | ||
function mockSend(statusCode) { | ||
assert.equal(statusCode, 406) | ||
function mockStatus(statusCode) { | ||
assert.equal(406, statusCode) | ||
done() | ||
return { end: noop } | ||
} | ||
middleware({ headers: { accept: 'jim,application/jsin,text/html,text/plain' } }, { send: mockSend }, function () { | ||
var headers = { accept: 'jim,application/jsin,text/html,text/plain' } | ||
middleware({ headers: headers }, { status: mockStatus }, function () { | ||
assert(false, 'should not call next()') | ||
@@ -50,14 +55,18 @@ }) | ||
it('should correct negotiate fill wildcard in "Accept" header', function (done) { | ||
middleware({ headers: { accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8' } }, {}, function () { | ||
done() | ||
}) | ||
middleware( | ||
{ headers: | ||
{ accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8' } | ||
}, {}, function () { | ||
done() | ||
}) | ||
}) | ||
it('should not be ok with "crapplication/json" in "Accept" header', function (done) { | ||
function mockSend(statusCode) { | ||
assert.equal(statusCode, 406) | ||
function mockStatus(statusCode) { | ||
assert.equal(406, statusCode) | ||
done() | ||
return { end: noop } | ||
} | ||
var accept = 'crapplication/json , text/html' | ||
middleware({ headers: { accept: accept } }, { send: mockSend }, function () { | ||
middleware({ headers: { accept: accept } }, { status: mockStatus }, function () { | ||
assert(false, 'should not call next()') | ||
@@ -64,0 +73,0 @@ }) |
@@ -13,3 +13,3 @@ var request = require('supertest') | ||
app.all('/', function (req, res) { | ||
res.send(200) | ||
res.status(200).end() | ||
}) | ||
@@ -16,0 +16,0 @@ }) |
@@ -18,3 +18,3 @@ var request = require('supertest') | ||
app.all('/', function (req, res) { | ||
res.send(200) | ||
res.status(200).end() | ||
}) | ||
@@ -21,0 +21,0 @@ }) |
@@ -5,2 +5,4 @@ var assert = require('assert') | ||
function noop() {} | ||
describe('middleware/cors unit tests', function () { | ||
@@ -31,5 +33,6 @@ | ||
function mockSend(statusCode) { | ||
function mockStatus(statusCode) { | ||
assert.equal(403, statusCode) | ||
done() | ||
return { end: noop } | ||
} | ||
@@ -41,3 +44,3 @@ | ||
createMiddleware(checkOrigin)({ headers: { origin: 'bar' } }, { send: mockSend }, function () { | ||
createMiddleware(checkOrigin)({ headers: { origin: 'bar' } }, { status: mockStatus}, function () { | ||
assert(false, 'should not call next()') | ||
@@ -59,3 +62,3 @@ }) | ||
{ 'Access-Control-Allow-Origin': 'http://127.0.0.1/' | ||
, 'Access-Control-Allow-Headers': 'Authorization, Content-Type, x-cf-date, *' | ||
, 'Access-Control-Allow-Headers': 'Authorization, Content-Type, x-cf-date, x-cf-ttl, *' | ||
, 'Access-Control-Request-Headers': '*' | ||
@@ -93,31 +96,31 @@ , 'Access-Control-Allow-Methods': 'GET, POST, OPTIONS, PUT, DELETE, PATCH' | ||
it('should OPTIONS set ‘content-length: 0’ for OPTIONS method', function (done) { | ||
it('should OPTIONS set ‘content-length: 0’ for OPTIONS method', function (done) { | ||
var headers = {} | ||
, allowed = [ 'http://127.0.0.1/' ] | ||
var headers = {} | ||
, allowed = [ 'http://127.0.0.1/' ] | ||
function checkOrigin(url, cb) { | ||
cb(null, true) | ||
} | ||
function checkOrigin(url, cb) { | ||
cb(null, true) | ||
} | ||
function mockEnd() { | ||
assert.equal(headers['Content-Length'], 0) | ||
done() | ||
} | ||
function mockEnd() { | ||
assert.equal(headers['Content-Length'], 0) | ||
done() | ||
} | ||
createMiddleware(checkOrigin)( | ||
{ headers: { origin: allowed[0] } | ||
, method: 'OPTIONS' | ||
createMiddleware(checkOrigin)( | ||
{ headers: { origin: allowed[0] } | ||
, method: 'OPTIONS' | ||
} | ||
, { end: mockEnd | ||
, set: function(key, value) { | ||
if (typeof key === 'object') { | ||
extend(headers, key) | ||
} else { | ||
headers[key] = value | ||
} | ||
} | ||
, { end: mockEnd | ||
, set: function(key, value) { | ||
if (typeof key === 'object') { | ||
extend(headers, key) | ||
} else { | ||
headers[key] = value | ||
} | ||
} | ||
}) | ||
}) | ||
}) | ||
}) | ||
}) |
@@ -14,5 +14,2 @@ var request = require('supertest') | ||
app.use(app.router) | ||
app.use(createMiddleware(logger)) | ||
app.get('/', function (req, res, next) { | ||
@@ -28,2 +25,3 @@ next(new Error('Test error')) | ||
app.use(createMiddleware(logger)) | ||
}) | ||
@@ -30,0 +28,0 @@ |
@@ -15,3 +15,3 @@ var request = require('supertest') | ||
app.get('/', function (req, res) { | ||
res.send(200) | ||
res.status(200).end() | ||
}) | ||
@@ -18,0 +18,0 @@ }) |
@@ -14,3 +14,3 @@ var request = require('supertest') | ||
app.get('/', function (req, res) { | ||
res.send(200) | ||
res.status(200).end() | ||
}) | ||
@@ -17,0 +17,0 @@ }) |
@@ -14,3 +14,3 @@ var request = require('supertest') | ||
app.get('/', function (req, res) { | ||
res.send(200) | ||
res.status(200).end() | ||
}) | ||
@@ -17,0 +17,0 @@ }) |
28792
6
749
68
+ Addedbody-parser@^1.14.1
+ Addedmorgan@^1.6.1
+ Addedresponse-time@^2.3.1
+ Addedarray-flatten@1.1.1(transitive)
+ Addedbasic-auth@2.0.1(transitive)
+ Addedbody-parser@1.20.3(transitive)
+ Addedbytes@3.1.2(transitive)
+ Addedcall-bind-apply-helpers@1.0.2(transitive)
+ Addedcall-bound@1.0.3(transitive)
+ Addedcontent-disposition@0.5.4(transitive)
+ Addedcookie@0.7.1(transitive)
+ Addeddestroy@1.2.0(transitive)
+ Addeddunder-proto@1.0.1(transitive)
+ Addedencodeurl@1.0.22.0.0(transitive)
+ Addedes-define-property@1.0.1(transitive)
+ Addedes-errors@1.3.0(transitive)
+ Addedes-object-atoms@1.1.1(transitive)
+ Addedetag@1.8.1(transitive)
+ Addedexpress@4.21.2(transitive)
+ Addedfinalhandler@1.3.1(transitive)
+ Addedforwarded@0.2.0(transitive)
+ Addedfresh@0.5.2(transitive)
+ Addedfunction-bind@1.1.2(transitive)
+ Addedget-intrinsic@1.2.7(transitive)
+ Addedget-proto@1.0.1(transitive)
+ Addedgopd@1.2.0(transitive)
+ Addedhas-symbols@1.1.0(transitive)
+ Addedhasown@2.0.2(transitive)
+ Addedhttp-errors@2.0.0(transitive)
+ Addediconv-lite@0.4.24(transitive)
+ Addedipaddr.js@1.9.1(transitive)
+ Addedmath-intrinsics@1.1.0(transitive)
+ Addedmerge-descriptors@1.0.3(transitive)
+ Addedmime@1.6.0(transitive)
+ Addedmorgan@1.10.0(transitive)
+ Addedms@2.1.3(transitive)
+ Addedobject-inspect@1.13.4(transitive)
+ Addedon-finished@2.4.1(transitive)
+ Addedpath-to-regexp@0.1.12(transitive)
+ Addedproxy-addr@2.0.7(transitive)
+ Addedqs@6.13.0(transitive)
+ Addedrange-parser@1.2.1(transitive)
+ Addedraw-body@2.5.2(transitive)
+ Addedsafe-buffer@5.1.25.2.1(transitive)
+ Addedsafer-buffer@2.1.2(transitive)
+ Addedsend@0.19.0(transitive)
+ Addedserve-static@1.16.2(transitive)
+ Addedsetprototypeof@1.2.0(transitive)
+ Addedside-channel@1.1.0(transitive)
+ Addedside-channel-list@1.0.0(transitive)
+ Addedside-channel-map@1.0.1(transitive)
+ Addedside-channel-weakmap@1.0.2(transitive)
+ Addedstatuses@2.0.1(transitive)
+ Addedtoidentifier@1.0.1(transitive)
+ Addedutils-merge@1.0.1(transitive)
- Removedaccepts@1.2.13(transitive)
- Removedbase64-url@1.2.1(transitive)
- Removedbasic-auth@1.0.4(transitive)
- Removedbasic-auth-connect@1.0.0(transitive)
- Removedbatch@0.5.3(transitive)
- Removedbody-parser@1.13.3(transitive)
- Removedbytes@2.1.02.4.0(transitive)
- Removedcommander@2.6.0(transitive)
- Removedcompressible@2.0.18(transitive)
- Removedcompression@1.5.2(transitive)
- Removedconnect@2.30.2(transitive)
- Removedconnect-timeout@1.6.2(transitive)
- Removedcontent-disposition@0.5.0(transitive)
- Removedcookie@0.1.3(transitive)
- Removedcookie-parser@1.3.5(transitive)
- Removedcore-util-is@1.0.3(transitive)
- Removedcrc@3.3.0(transitive)
- Removedcsrf@3.0.6(transitive)
- Removedcsurf@1.8.3(transitive)
- Removeddebug@2.2.0(transitive)
- Removeddepd@1.0.11.1.2(transitive)
- Removeddestroy@1.0.31.0.4(transitive)
- Removederrorhandler@1.4.3(transitive)
- Removedescape-html@1.0.2(transitive)
- Removedetag@1.7.0(transitive)
- Removedexpress@3.21.2(transitive)
- Removedexpress-session@1.11.3(transitive)
- Removedfinalhandler@0.4.0(transitive)
- Removedforwarded@0.1.2(transitive)
- Removedfresh@0.3.0(transitive)
- Removedhttp-errors@1.3.1(transitive)
- Removediconv-lite@0.4.110.4.13(transitive)
- Removedipaddr.js@1.0.5(transitive)
- Removedisarray@0.0.1(transitive)
- Removedmerge-descriptors@1.0.0(transitive)
- Removedmethod-override@2.3.10(transitive)
- Removedmime@1.3.4(transitive)
- Removedmime-db@1.53.0(transitive)
- Removedminimist@0.0.8(transitive)
- Removedmkdirp@0.5.1(transitive)
- Removedmorgan@1.6.1(transitive)
- Removedms@0.7.10.7.2(transitive)
- Removedmultiparty@3.3.2(transitive)
- Removednegotiator@0.5.3(transitive)
- Removedpause@0.1.0(transitive)
- Removedproxy-addr@1.0.10(transitive)
- Removedqs@4.0.0(transitive)
- Removedrandom-bytes@1.0.0(transitive)
- Removedrange-parser@1.0.3(transitive)
- Removedraw-body@2.1.7(transitive)
- Removedreadable-stream@1.1.14(transitive)
- Removedrndm@1.2.0(transitive)
- Removedsend@0.13.00.13.2(transitive)
- Removedserve-favicon@2.3.2(transitive)
- Removedserve-index@1.7.3(transitive)
- Removedserve-static@1.10.3(transitive)
- Removedstatuses@1.2.11.5.0(transitive)
- Removedstream-counter@0.2.0(transitive)
- Removedstring_decoder@0.10.31(transitive)
- Removedtsscmp@1.0.5(transitive)
- Removeduid-safe@2.0.02.1.4(transitive)
- Removedutils-merge@1.0.0(transitive)
- Removedvary@1.0.1(transitive)
- Removedvhost@3.0.2(transitive)
Updatedexpress@^4.13.3