Comparing version 0.5.9 to 0.5.10
@@ -1,3 +0,3 @@ | ||
// Dependencies | ||
// ------------ | ||
// __Dependencies__ | ||
var util = require('util'); | ||
@@ -8,3 +8,3 @@ var express = require('express'); | ||
var url = require('url'); | ||
var userMiddlewareSchema = require('./userMiddlewareSchema'); | ||
var middleware = { | ||
@@ -18,22 +18,4 @@ configure: require('./middleware/configure'), | ||
// Private Static Members | ||
// ---------------------- | ||
// __Private Static Members__ | ||
// Create a data structure to store user-defined middleware | ||
function createEmptyMiddlewareHash () { | ||
var o = {}; | ||
['request', 'query', 'documents'].forEach(function (stage) { | ||
o[stage] = {}; | ||
['instance', 'collection'].forEach(function (howMany) { | ||
o[stage][howMany] = {}; | ||
['head', 'get', 'post', 'put', 'del'].forEach(function (verb) { | ||
o[stage][howMany][verb] = []; | ||
}); | ||
}); | ||
}); | ||
return o; | ||
} | ||
// Cascade optional paramaters into a single hash | ||
@@ -61,8 +43,11 @@ function cascadeArguments (stage, howMany, verbs, middleware) { | ||
// Module Definition | ||
// __Module Definition__ | ||
var Controller = module.exports = function (options) { | ||
// __Defaults__ | ||
// Marshal string into a hash | ||
if (typeof options === 'string') options = { singular: options }; | ||
// Validate singular & basePath | ||
// __Validation__ | ||
if (!options.singular) throw new Error('Must provide the Mongoose schema name'); | ||
@@ -73,8 +58,12 @@ if (options.basePath) { | ||
} | ||
if (options.findBy && !mongoose.model(options.singular).schema.path(options.findBy).options.unique) { | ||
throw new Error('findBy path for ' + options.singular + ' not unique'); | ||
} | ||
// *Private Instance Members* | ||
// __Private Instance Variables__ | ||
var controller = express(); | ||
var initialized = false; | ||
var model = mongoose.model(options.singular); | ||
var userMiddlewareFor = createEmptyMiddlewareHash(); | ||
var userMiddlewareFor = userMiddlewareSchema(); | ||
var basePath = options.basePath ? options.basePath : '/'; | ||
@@ -85,8 +74,4 @@ var separator = (basePath === '/' ? '' : '/'); | ||
// Validate findBy | ||
if (options.findBy && !model.schema.path(options.findBy).options.unique) { | ||
throw new Error('findBy path for ' + options.singular + ' not unique'); | ||
} | ||
// __Private Instance Methods__ | ||
// *Private Instance Methods* | ||
// Parse the options hash and recurse `f` with parsed paramaters. Execute `g` | ||
@@ -117,3 +102,3 @@ // for each verb. | ||
// Register user middleware to be activated later | ||
// A method used to register user middleware to be activated during intialization. | ||
function registerMiddleware (options) { | ||
@@ -140,3 +125,3 @@ if (initialized) { | ||
// Activate user middleware that was registered previously | ||
// A method used to activate user middleware that was previously registered. | ||
function activateMiddleware (options) { | ||
@@ -159,4 +144,5 @@ if (initialized) throw new Error("Can't activate middleware after the controller has been initialized."); | ||
// Public Methods | ||
// -------------- | ||
// __Public Methods__ | ||
// A method used to register request-stage middleware. | ||
controller.request = function (howMany, verbs, middleware) { | ||
@@ -168,6 +154,7 @@ var cascaded = cascadeArguments('request', howMany, verbs, middleware); | ||
// A method used to register query-stage middleware. | ||
controller.query = function (howMany, verbs, middleware) { | ||
var cascaded = cascadeArguments('query', howMany, verbs, middleware); | ||
// Prevent explicitly setting query:post middleware. Implicitly adding | ||
// query:post middleware is ignored. | ||
// Prevent explicitly setting query-stage POST middleware. Implicitly adding | ||
// this middleware is ignored. | ||
if (cascaded.verbs && cascaded.verbs.indexOf('post') !== -1) { | ||
@@ -180,2 +167,3 @@ throw new Error('POST cannot have query middleware'); | ||
// A method used to register document-stage middleware. | ||
controller.documents = function (howMany, verbs, middleware) { | ||
@@ -187,6 +175,10 @@ var cascaded = cascadeArguments('documents', howMany, verbs, middleware); | ||
// A method used to intialize the controller and activate user middleware. It | ||
// may be called multiple times, but will trigger intialization only once. | ||
controller.initialize = function () { | ||
if (initialized) return controller; | ||
// Allow/Accept headers | ||
// __Request-Stage Middleware__ | ||
// Activate middleware that sets the Allow & Accept headers | ||
activateMiddleware({ | ||
@@ -197,3 +189,3 @@ stage: 'request', | ||
// Process the request before building the query. | ||
// Activate middleware to set request.baucis.conditions for find/remove | ||
activateMiddleware({ | ||
@@ -205,2 +197,3 @@ stage: 'request', | ||
}); | ||
// Next, activate the request-stage user middleware. | ||
activateMiddleware({ | ||
@@ -210,2 +203,3 @@ stage: 'request', | ||
}); | ||
// Activate middleware to build the query (except for POST requests). | ||
activateMiddleware({ | ||
@@ -216,3 +210,7 @@ stage: 'request', | ||
// Query has been created (except for POST) | ||
// __Query-Stage Middleware__ | ||
// The query will have been created (except for POST, which doesn't use a | ||
// find or remove query). | ||
// Activate middleware to handle controller and query options. | ||
activateMiddleware({ | ||
@@ -223,11 +221,15 @@ stage: 'query', | ||
// Delete any POST-stage query middleware that was added implicitly | ||
delete userMiddlewareFor['query']['instance']['post']; | ||
delete userMiddlewareFor['query']['collection']['post']; | ||
// Delete any query-stage POST middleware that was added implicitly. | ||
userMiddlewareFor.query.instance.post = []; | ||
userMiddlewareFor.query.collection.post = []; | ||
// Activate user middleware for the query-stage | ||
activateMiddleware({ | ||
stage: 'query', | ||
verbs: 'head get put del', | ||
middleware: userMiddlewareFor['query'] | ||
}); | ||
// Activate middleware to execute the query: | ||
// Get the count for HEAD requests. | ||
activateMiddleware({ | ||
@@ -238,2 +240,3 @@ stage: 'query', | ||
}); | ||
// Execute the find or remove query for GET and DELETE. | ||
activateMiddleware({ | ||
@@ -244,2 +247,3 @@ stage: 'query', | ||
}); | ||
// Create the documents for a POST request. | ||
activateMiddleware({ | ||
@@ -251,2 +255,3 @@ stage: 'query', | ||
}); | ||
// Update the documents specified for a PUT request. | ||
activateMiddleware({ | ||
@@ -259,3 +264,5 @@ stage: 'query', | ||
// Set Link header if desired (must come after exec or else query gets count) | ||
// Activate some middleware that will set the Link header when that feature | ||
// is enabled. (This must come after exec or else the count is | ||
// returned for all subsequqent executions of the query.) | ||
if (this.get('relations') === true) { | ||
@@ -274,3 +281,5 @@ activateMiddleware({ | ||
// Documents/count have/has been created | ||
// __Document-Stage Middleware__ | ||
// Activate the middleware that sets the `Last-Modified` header when appropriate. | ||
activateMiddleware({ | ||
@@ -280,2 +289,3 @@ stage: 'documents', | ||
}); | ||
// Activate the the document-stage user middleware. | ||
activateMiddleware({ | ||
@@ -285,2 +295,3 @@ stage: 'documents', | ||
}); | ||
// Activate the middleware that sends the resulting document(s) or count. | ||
activateMiddleware({ | ||
@@ -291,2 +302,4 @@ stage: 'documents', | ||
// __Finalize Initialization__ | ||
// The controller is initialized and we don't need the intermiediate data | ||
@@ -300,4 +313,4 @@ // structure any more. | ||
// Configuration | ||
// ------------- | ||
// __Configuration__ | ||
Object.keys(options).forEach(function (key) { | ||
@@ -315,3 +328,4 @@ controller.set(key, options[key]); | ||
// Basic middleware | ||
// __Initial Middleware__ | ||
// Middleware for parsing JSON requests | ||
@@ -318,0 +332,0 @@ controller.use(express.json()); |
14
index.js
@@ -1,3 +0,2 @@ | ||
// Dependencies | ||
// ------------ | ||
// __Dependencies__ | ||
var url = require('url'); | ||
@@ -7,9 +6,7 @@ var express = require('express'); | ||
// Private Members | ||
// --------------- | ||
// __Private Members__ | ||
var controllers = []; | ||
var app = express(); | ||
// Module Definition | ||
// ----------------- | ||
var app = express(); | ||
// __Module Definition__ | ||
var baucis = module.exports = function (options) { | ||
@@ -31,4 +28,3 @@ options || (options = {}); | ||
// Public Methods | ||
// -------------- | ||
// __Public Methods__ | ||
baucis.rest = function (options) { | ||
@@ -35,0 +31,0 @@ var controller = Controller(options); |
@@ -0,2 +1,4 @@ | ||
// __Module Definition__ | ||
var middleware = module.exports = { | ||
// Set the conditions used for finding/removing documents | ||
conditions: function (request, response, next) { | ||
@@ -3,0 +5,0 @@ if (!request.query.conditions) return next(); |
@@ -1,8 +0,6 @@ | ||
// Dependencies | ||
// ------------ | ||
// __Dependencies__ | ||
var url = require('url'); | ||
var mongoose = require('mongoose'); | ||
// Module Definition | ||
// ----------------- | ||
// __Module Definition__ | ||
var middleware = module.exports = { | ||
@@ -38,3 +36,5 @@ lastModified: function (request, response, next) { | ||
var ids; | ||
var location; | ||
var findBy = request.app.get('findBy'); | ||
var basePath = request.originalUrl; | ||
var documents = request.baucis.documents; | ||
@@ -45,15 +45,13 @@ | ||
if (request.baucis.noBody) { | ||
return response.send(); | ||
} | ||
if (request.baucis.noBody) return response.send(); | ||
// If it's a document count (e.g. the result of a DELETE), send it back and short-circuit | ||
if (typeof documents === 'number') { | ||
return response.json(documents); | ||
} | ||
// If it's a document count (e.g. the result of a DELETE), send it back and | ||
// short-circuit. | ||
if (typeof documents === 'number') return response.json(documents); | ||
// If count mode is set, send the length, or send 1 for single document | ||
if (request.baucis.count) { | ||
if (Array.isArray(documents)) return response.send(documents.length); | ||
else return response.json(1); | ||
if (Array.isArray(documents)) response.send(documents.length); | ||
else response.json(1); | ||
return; | ||
} | ||
@@ -65,15 +63,19 @@ | ||
if (documents.get) { | ||
request.baucis.location = url.resolve(request.app.get('basePath'), documents.get(findBy)); | ||
location = url.resolve(basePath, documents.get(findBy).toString()); | ||
} | ||
} | ||
else if (documents.length === 1 && documents[0] instanceof mongoose.Document) { | ||
request.baucis.location = url.resolve(request.app.get('basePath'), documents[0].get(findBy)); | ||
location = url.resolve(basePath, documents[0].get(findBy).toString()); | ||
} | ||
else if (documents.every(function (doc) { return doc instanceof mongoose.Document })) { | ||
ids = documents.map(function (doc) { return doc.get(findBy) }); | ||
request.baucis.location = request.app.get('basePath') + '?conditions={ _id: { $in: [' + ids.join() + '] } }'; | ||
ids = documents.map(function (doc) { return '"' + doc.get(findBy) + '"' }); | ||
if (ids.every(function (id) { return id })) { | ||
location = basePath + '?conditions={ "' + findBy + '": { "$in": [' + ids.join() + '] } }'; | ||
} | ||
} | ||
if (location) response.set('Location', location); | ||
response.json(documents); | ||
} | ||
}; |
@@ -1,8 +0,6 @@ | ||
// Dependencies | ||
// ------------ | ||
// __Dependencies__ | ||
var async = require('async'); | ||
var extend = require('util')._extend; | ||
// Module Definition | ||
// ----------------- | ||
// __Module Definition__ | ||
var middleware = module.exports = { | ||
@@ -9,0 +7,0 @@ exec: function (request, response, next) { |
@@ -1,3 +0,2 @@ | ||
// Dependencies | ||
// ------------ | ||
// __Dependencies__ | ||
var url = require('url'); | ||
@@ -7,4 +6,3 @@ var extend = require('util')._extend; | ||
// Module Definition | ||
// ----------------- | ||
// __Module Definition__ | ||
var middleware = module.exports = { | ||
@@ -11,0 +9,0 @@ // Add "Link" header field, with some basic defaults |
@@ -1,3 +0,2 @@ | ||
// Private Members | ||
// --------------- | ||
// __Private Members__ | ||
function getFindCondition (request) { | ||
@@ -9,4 +8,3 @@ var conditions = {}; | ||
// Module Definition | ||
// ----------------- | ||
// __Module Definition__ | ||
var middleware = module.exports = { | ||
@@ -13,0 +11,0 @@ instance: { |
@@ -5,3 +5,3 @@ { | ||
"homepage": "https://github.com/wprl/baucis", | ||
"version": "0.5.9", | ||
"version": "0.5.10", | ||
"main": "index.js", | ||
@@ -8,0 +8,0 @@ "scripts": { |
@@ -1,3 +0,3 @@ | ||
baucis v0.5.9 | ||
============= | ||
baucis v0.5.10 | ||
============== | ||
@@ -4,0 +4,0 @@ Baucis is Express middleware that creates configurable REST APIs using Mongoose schemata. |
@@ -74,3 +74,3 @@ var expect = require('expect.js'); | ||
var options = { | ||
url: 'http://localhost:8012/api/v1/stores/XYZ/foos', | ||
url: 'http://localhost:8012/api/v1/stores/XYZ/arbitrary', | ||
json: true | ||
@@ -112,3 +112,3 @@ }; | ||
it('should allow using middleware' /*, function (done) { | ||
it('should allow using middleware', function (done) { | ||
var options = { | ||
@@ -118,12 +118,11 @@ url: 'http://localhost:8012/api/v1/stores', | ||
}; | ||
request.get(options, function (err, response, body) { | ||
request.del(options, function (err, response, body) { | ||
if (err) return done(err); | ||
expect(response).to.have.property('statusCode', 200); | ||
expect(body).to.be('Poncho!'); | ||
expect(response.headers['x-poncho']).to.be('Poncho!'); | ||
done(); | ||
}); | ||
}*/); | ||
}); | ||
it('should allow using middleware mounted at a path'/*, function (done) { | ||
it('should allow using middleware mounted at a path', function (done) { | ||
var options = { | ||
@@ -133,13 +132,15 @@ url: 'http://localhost:8012/api/v1/stores/binfo', | ||
}; | ||
request.get(options, function (err, response, body) { | ||
request.post(options, function (err, response, body) { | ||
if (err) return done(err); | ||
expect(response.statusCode).to.be(200); | ||
expect(body).to.be('OK!'); | ||
expect(response).to.have.property('statusCode', 200); | ||
expect(body).to.be('Poncho!'); | ||
done(); | ||
}); | ||
} */); | ||
}); | ||
it('should disallow adding handlers after initialization', function (done) { | ||
var f = function () { controller.request('get', function () {}) }; | ||
expect(f).to.throwException(); | ||
var controller = baucis.rest('store'); | ||
controller.initialize(); | ||
var register = function () { controller.request('get', function () {}) }; | ||
expect(register).to.throwException(/Can't add middleware after the controller has been initialized./); | ||
done(); | ||
@@ -149,5 +150,5 @@ }); | ||
it('should not allow query middleware to be explicitly registered for POST', function (done) { | ||
var badController = baucis.rest('store'); | ||
var register = function () { badController.query('get put head del post', function () {}) }; | ||
expect(register).to.throwException(); | ||
var controller = baucis.rest('store'); | ||
var register = function () { controller.query('get put head del post', function () {}) }; | ||
expect(register).to.throwException(/POST cannot have query middleware/); | ||
done(); | ||
@@ -154,0 +155,0 @@ }); |
@@ -12,3 +12,2 @@ var expect = require('expect.js'); | ||
it('should delete the addressed document', function (done) { | ||
// make sure it's there | ||
var shitake = vegetables[3]; | ||
@@ -19,3 +18,2 @@ var options = { | ||
}; | ||
request.del(options, function (error, response, body) { | ||
@@ -22,0 +20,0 @@ if (error) return done(error); |
@@ -44,2 +44,11 @@ var mongoose = require('mongoose'); | ||
controller.use('/binfo', function (request, response, next) { | ||
response.json('Poncho!'); | ||
}); | ||
controller.use(function (request, response, next) { | ||
response.set('X-Poncho', 'Poncho!'); | ||
next(); | ||
}); | ||
controller.get('/info', function (request, response, next) { | ||
@@ -49,3 +58,3 @@ response.json('OK!'); | ||
controller.get('/:id/foos', function (request, response, next) { | ||
controller.get('/:id/arbitrary', function (request, response, next) { | ||
response.json(request.params.id); | ||
@@ -52,0 +61,0 @@ }); |
@@ -21,6 +21,7 @@ var expect = require('expect.js'); | ||
expect(response.statusCode).to.equal(201); | ||
expect(body._id).not.to.be.empty(); // TODO check it's an ObjectID | ||
expect(body._id).not.to.be.empty(); | ||
expect(response.headers.location).to.equal('/api/v1/vegetables/' + body._id); | ||
var options = { | ||
url: 'http://localhost:8012/api/v1/vegetables/' + body._id, | ||
url: 'http://localhost:8012' + response.headers.location, | ||
json: true | ||
@@ -37,2 +38,29 @@ }; | ||
it('should allow posting multiple documents at once', function (done) { | ||
var options = { | ||
url: 'http://localhost:8012/api/v1/vegetables/', | ||
json: [{ name: 'Catnip' }, { name: 'Cattail'}] | ||
}; | ||
request.post(options, function (error, response, body) { | ||
if (error) return done(error); | ||
expect(response.statusCode).to.equal(201); | ||
expect(body[0]._id).not.to.be.empty(); | ||
expect(body[1]._id).not.to.be.empty(); | ||
var options = { | ||
url: 'http://localhost:8012' + response.headers.location, | ||
json: true | ||
}; | ||
request.get(options, function (error, response, body) { | ||
if (error) return done(error); | ||
expect(response).to.have.property('statusCode', 200); | ||
expect(body).to.have.property('length', 2); | ||
expect(body[0]).to.have.property('name', 'Catnip'); | ||
expect(body[1]).to.have.property('name', 'Cattail'); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
it('should fire pre save Mongoose middleware', function (done) { | ||
@@ -39,0 +67,0 @@ fixtures.vegetable.preCount = 0; |
@@ -7,7 +7,3 @@ var expect = require('expect.js'); | ||
describe('PUT plural', function () { | ||
before(fixtures.vegetable.init); | ||
beforeEach(fixtures.vegetable.create); | ||
after(fixtures.vegetable.deinit); | ||
it('should replace entire collection with given new collection', function (done) { | ||
it('should replace entire collection with given new collection... maybe'); /*, function (done) { | ||
return done(); // TODO unimplemented | ||
@@ -29,4 +25,4 @@ | ||
}); | ||
}); | ||
}); */ | ||
}); | ||
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
304802
37
2041