Comparing version 0.5.7 to 0.5.8
@@ -64,3 +64,3 @@ // Dependencies | ||
// Validation | ||
// Validate singular & basePath | ||
if (!options.singular) throw new Error('Must provide the Mongoose schema name'); | ||
@@ -72,5 +72,6 @@ if (options.basePath) { | ||
// Private Instance Members | ||
// *Private Instance Members* | ||
var controller = express(); | ||
var initialized = false; | ||
var model = mongoose.model(options.singular); | ||
var userMiddlewareFor = createEmptyMiddlewareHash(); | ||
@@ -82,2 +83,8 @@ var basePath = options.basePath ? options.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* | ||
// Parse the options hash and recurse `f` with parsed paramaters. Execute `g` | ||
@@ -278,3 +285,3 @@ // for each verb. | ||
controller.set('model', mongoose.model(options.singular)); | ||
controller.set('model', model); | ||
controller.set('plural', options.plural || lingo.en.pluralize(options.singular)); | ||
@@ -281,0 +288,0 @@ controller.set('findBy', options.findBy || '_id'); |
// Dependencies | ||
// ------------ | ||
var url = require('url'); | ||
var mongoose = require('mongoose'); | ||
@@ -37,2 +38,3 @@ // Module Definition | ||
var ids; | ||
var findBy = request.app.get('findBy'); | ||
var documents = request.baucis.documents; | ||
@@ -58,11 +60,14 @@ | ||
// Otherwise, set the location and send JSON document(s) | ||
if (!Array.isArray(documents)) { | ||
request.baucis.location = url.resolve(request.app.get('basePath'), documents.id); | ||
// Otherwise, set the location and send JSON document(s). Don't set location if documents | ||
// don't have IDs for whatever reason e.g. custom middleware. | ||
if (!Array.isArray(documents) && documents instanceof mongoose.Document) { | ||
if (documents.get) { | ||
request.baucis.location = url.resolve(request.app.get('basePath'), documents.get(findBy)); | ||
} | ||
} | ||
else if (documents.length === 1) { | ||
request.baucis.location = url.resolve(request.app.get('basePath'), documents[0].id); | ||
else if (documents.length === 1 && documents[0] instanceof mongoose.Document) { | ||
request.baucis.location = url.resolve(request.app.get('basePath'), documents[0].get(findBy)); | ||
} | ||
else { | ||
ids = documents.map(function (doc) { return doc.id }); | ||
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() + '] } }'; | ||
@@ -69,0 +74,0 @@ } |
@@ -20,3 +20,3 @@ // Private Members | ||
}, | ||
// Retrive the addressed document | ||
// Retrieve the addressed document | ||
get: function (request, response, next) { | ||
@@ -23,0 +23,0 @@ var Model = request.app.get('model'); |
@@ -5,3 +5,3 @@ { | ||
"homepage": "https://github.com/wprl/baucis", | ||
"version": "0.5.7", | ||
"version": "0.5.8", | ||
"main": "index.js", | ||
@@ -8,0 +8,0 @@ "scripts": { |
@@ -1,2 +0,2 @@ | ||
baucis v0.5.7 | ||
baucis v0.5.8 | ||
============= | ||
@@ -23,10 +23,5 @@ | ||
var Vegetable = new mongoose.Schema({ | ||
name: String | ||
}); | ||
var Vegetable = new mongoose.Schema({ name: String }); | ||
var Fruit = new mongoose.Schema({ name: String }); | ||
var Fruit = new mongoose.Schema({ | ||
name: String | ||
}); | ||
// Note that Mongoose middleware will be executed as usual | ||
@@ -73,2 +68,3 @@ Vegetable.pre('save', function () { ... }); | ||
* [Example REST API server built with Node and Baucis](//github.com/wprl/baucis-example) | ||
* [Examples with Backbone](examples/Backbone.js) | ||
@@ -100,5 +96,9 @@ * [Examples with jQuery](examples/jQuery.js) | ||
For simple controllers, only the schema name need be passed. | ||
var controller = baucis.rest('robot'); | ||
Controllers are Express apps; they may be used as such. | ||
var controller = baucis.rest({ singular: 'robot' }); | ||
var controller = baucis.rest('robot'); | ||
@@ -116,3 +116,2 @@ // Add middleware before API routes | ||
// Do other stuff... | ||
@@ -139,16 +138,4 @@ controller.set('some option name', 'value'); | ||
The first form is the most specific. The first argument lets you specify whether the middleware applies to document instances (paths like `/foos/:id`) or to collection requests (paths like `/foos`). The second argument is a space-delimted list of HTTP verbs that the middleware should be applied to. The third argument is the middleware function to add or an array of middleware functions. | ||
To apply middleware to all API routes, just pass the function or array to the method for the appropriate stage: | ||
controller.request('instance', 'head get del', middleware); | ||
controller.request('collection', 'post', middleware); | ||
To add middleware that applies to both document instances and collections, the first argument is omitted: | ||
controller.query('get put', function (request, response, next) { | ||
// do something with request.baucis.query | ||
next(); | ||
}); | ||
To apply middleware to all API routes, just pass the function or array: | ||
controller.request(function (request, response, next) { | ||
@@ -160,20 +147,21 @@ if (request.isAuthenticated()) return next(); | ||
controller.documents(function (request, response, next) { | ||
var ok = true; | ||
if (typeof request.baucis.documents === 'number') return next(); | ||
[].concat(request.baucis.documents).forEach(function (doc) { | ||
if (!ok) return; | ||
if (!doc.iSelected('owner') { | ||
ok = false; | ||
next(new Error('Must select owner')); | ||
return; | ||
} | ||
if (doc.owner !== request.user.id) { | ||
ok = false; | ||
next(new Error('User does not own this.')); | ||
return; | ||
} | ||
}); | ||
if (ok) next(); | ||
if (!Array.isArray(request.baucis.documents)) return next(); | ||
request.baucis.documents.pop(); | ||
next(); | ||
}); | ||
To add middleware that applies only to specific HTTP verbs, use the second form. It adds a paramater that must contain a space-delimted list of HTTP verbs that the middleware should be applied to. | ||
controller.query('head get put', function (request, response, next) { | ||
request.baucis.query.sort('-created'); | ||
next(); | ||
}); | ||
The final form is the most specific. The first argument lets you specify whether the middleware applies to document instances (paths like `/foos/:id`) or to collection requests (paths like `/foos`). | ||
controller.request('instance', 'head get del', middleware); | ||
controller.request('collection', 'post', middleware); | ||
Controller Options | ||
@@ -210,5 +198,3 @@ ------------------ | ||
var controller = baucis.rest({ | ||
singular: 'foo' | ||
}); | ||
var controller = baucis.rest('foo'); | ||
@@ -215,0 +201,0 @@ // Embed the subcontroller at /foos/:fooId/bars |
@@ -30,5 +30,5 @@ var expect = require('expect.js'); | ||
expect(response.statusCode).to.be(200); | ||
expect(body).to.have.property('length', 2); | ||
expect(body).to.have.property('length', 3); | ||
expect(body[0]).to.have.property('color', 'Yellow'); | ||
expect(body[0]).not.to.have.property('name'); | ||
expect(body[0]).to.have.property('name', 'Cheddar'); | ||
expect(body[0]).not.to.have.property('_id'); | ||
@@ -39,2 +39,23 @@ done(); | ||
it('should support finding documents with custom findBy field', function (done) { | ||
var options = { | ||
url: 'http://localhost:8012/api/v1/cheeses/Camembert', | ||
json: true | ||
}; | ||
request.get(options, function (err, response, body) { | ||
if (err) return done(err); | ||
expect(response.statusCode).to.be(200); | ||
expect(body).to.have.property('color', 'White'); | ||
done(); | ||
}); | ||
}); | ||
it('should disallow adding a non-unique findBy field', function (done) { | ||
var makeController = function () { | ||
baucis.rest({ singular: 'cheese', findBy: 'color' }); | ||
}; | ||
expect(makeController).to.throwException(); | ||
done(); | ||
}); | ||
it('should allow adding arbitrary routes', function (done) { | ||
@@ -41,0 +62,0 @@ var options = { |
@@ -26,4 +26,4 @@ var mongoose = require('mongoose'); | ||
var Cheese = new Schema({ | ||
name: { type: String, required: true }, | ||
color: { type: String, required: true } | ||
name: { type: String, required: true, unique: true }, | ||
color: { type: String, required: true, select: false } | ||
}); | ||
@@ -43,5 +43,3 @@ | ||
controller = baucis.rest({ | ||
singular: 'store' | ||
}); | ||
controller = baucis.rest('store'); | ||
@@ -60,3 +58,4 @@ controller.get('/info', function (request, response, next) { | ||
singular: 'cheese', | ||
select: '-_id color' | ||
select: '-_id +color name', | ||
findBy: 'name' | ||
}) | ||
@@ -92,3 +91,7 @@ | ||
var cheeses = [{ name: 'Cheddar', color: 'Yellow' }, { name: 'Hunstman', color: 'Yellow, Blue, White' }]; | ||
var cheeses = [ | ||
{ name: 'Cheddar', color: 'Yellow' }, | ||
{ name: 'Hunstman', color: 'Yellow, Blue, White' }, | ||
{ name: 'Camembert', color: 'White' } | ||
]; | ||
@@ -95,0 +98,0 @@ mongoose.model('cheese').create(cheeses, function (error) { |
293384
1989
204