Comparing version 1.1.2 to 1.1.3
@@ -43,3 +43,3 @@ 'use strict'; | ||
return pool(r.table(config.table).insert(data, {returnChanges: true})).then(function(res){ return res.changes[0].new_val; }); | ||
return pool(r.table(config.table).insert(data, {returnChanges: true})).then(function(res){ return res.changes[0] ? res.changes[0].new_val : null; }); | ||
} | ||
@@ -58,3 +58,3 @@ | ||
return pool(r.table(config.table).get(id).delete({returnChanges: true})).then(function(res){ return res.changes[0].old_val; }); | ||
return pool(r.table(config.table).get(id).delete({returnChanges: true})).then(function(res){ return res.changes[0] ? res.changes[0].old_val : null; }); | ||
} | ||
@@ -125,3 +125,3 @@ | ||
var err = validator.validate(schema, data); | ||
if(err) return Q.reject(err); | ||
if(err) return Q.reject(new ValidationError(null, err.validation)); | ||
@@ -128,0 +128,0 @@ return pool(r.table(config.table).get(id).replace(data, {returnChanges: true})).then(function(res){ |
@@ -6,2 +6,10 @@ 'use strict'; | ||
function NotFoundError(message, validation) { | ||
this.name = 'NotFoundError'; | ||
this.message = message || 'Resource not found.'; | ||
this.validation = validation || {}; | ||
} | ||
NotFoundError.prototype = new Error(); | ||
NotFoundError.prototype.constructor = NotFoundError; | ||
module.exports = function(core) { | ||
@@ -31,7 +39,7 @@ var router = express.Router(); | ||
core.save(req.params.id, req.body) | ||
.catch(next) | ||
.then(function(answer){ | ||
if(!answer) return res.status(404).send(); | ||
if(!answer) return next(new NotFoundError); | ||
return res.status(200).send(answer); | ||
}); | ||
}) | ||
.catch(next); | ||
}); | ||
@@ -43,3 +51,3 @@ | ||
.then(function(answer){ | ||
if(!answer) return res.status(404).send(); | ||
if(!answer) return next(new NotFoundError); | ||
return res.status(200).send(answer); | ||
@@ -53,7 +61,7 @@ }) | ||
core.get(req.params.id) | ||
.catch(next) | ||
.then(function(answer){ | ||
if(!answer) return res.status(404).send(); | ||
if(!answer) return next(new NotFoundError); | ||
return res.status(200).send(answer); | ||
}); | ||
}) | ||
.catch(next); | ||
}); | ||
@@ -69,3 +77,3 @@ | ||
} catch (e) { | ||
return res.status(400).send({message: '`clue` is invalid JSON.'}); | ||
return next(new Error('`clue` is invalid JSON.')); | ||
} | ||
@@ -78,3 +86,3 @@ | ||
} catch (e) { | ||
return res.status(400).send({message: '`criteria` is invalid JSON.'}); | ||
return next(new Error('`criteria` is invalid JSON.')); | ||
} | ||
@@ -89,3 +97,9 @@ | ||
// handle transactional errors | ||
router.use(function(err, req, res, next) { | ||
res.status(err.name === 'NotFoundError' ? 404 : 400).send({message: err.message}); | ||
next(err); | ||
}); | ||
return router; | ||
} |
@@ -5,3 +5,3 @@ { | ||
"author": "Mike Marcacci <mike.marcacci@thecontrolgroup.com>", | ||
"version": "1.1.2", | ||
"version": "1.1.3", | ||
"main": "./lib/core/index.js", | ||
@@ -29,6 +29,7 @@ "repository": { | ||
"devDependencies": { | ||
"chai": "^1.10.0", | ||
"lodash": "^2.4.1", | ||
"mocha": "~2.0.1", | ||
"chai": "^1.10.0", | ||
"lodash": "^2.4.1" | ||
"supertest": "^0.15.0" | ||
} | ||
} |
@@ -24,12 +24,23 @@ 'use strict'; | ||
// handle arrdb errors | ||
jennings.$arrdb.on('error', function(err){ | ||
// NOTE: this is where one would fire off an alert, kill this process, or | ||
// remove this node from a load balancer. By default, we'll just use continue | ||
// to use our local cache until we're able to reconnect. | ||
console.error(err); | ||
jennings.$arrdb.once('reconnect', function(){ | ||
// NOTE: this is where one would re-join a load balancer, etc. | ||
}); | ||
}); | ||
// add to the server | ||
app.use(config.prefix, jennings.router); | ||
// handle transactional errors | ||
app.use(function(err, req, res, next) { | ||
res.status(400).send({message: err.message}); | ||
}); | ||
// start listening | ||
app.listen(config.port); | ||
} |
@@ -8,3 +8,3 @@ 'use strict'; | ||
describe('Core', function() { | ||
var insertedId; | ||
var createdId; | ||
@@ -40,3 +40,3 @@ before(function(){ | ||
.then(function(answer){ | ||
insertedId = answer.id; | ||
createdId = answer.id; | ||
delete answer.id; | ||
@@ -50,3 +50,3 @@ assert.deepEqual(answer, data); | ||
it('rejects an invalid save', function(done){ | ||
core.save(insertedId, {foo: 'bar'}) | ||
core.save(createdId, {foo: 'bar'}) | ||
.then(function(){ done(new Error('should not pass validation')); }) | ||
@@ -58,3 +58,3 @@ .catch(function(){ done(); }); | ||
var data = { | ||
id: insertedId, | ||
id: createdId, | ||
data: {}, | ||
@@ -87,5 +87,5 @@ criteria: [ | ||
it('accepts an existing get', function(done){ | ||
core.get(insertedId) | ||
core.get(createdId) | ||
.then(function(answer){ | ||
assert.equal(answer.id, insertedId); | ||
assert.equal(answer.id, createdId); | ||
done(); | ||
@@ -135,5 +135,5 @@ }) | ||
it('accepts an existing delete', function(done){ | ||
core.delete(insertedId) | ||
core.delete(createdId) | ||
.then(function(answer){ | ||
assert.equal(answer.id, insertedId); | ||
assert.equal(answer.id, createdId); | ||
done(); | ||
@@ -140,0 +140,0 @@ }) |
@@ -1,27 +0,174 @@ | ||
// 'use strict'; | ||
'use strict'; | ||
// var assert = require('chai').assert; | ||
// var config = require('../init.js'); | ||
// var core; | ||
var assert = require('chai').assert; | ||
var config = require('../init.js'); | ||
var core, request; | ||
// describe('API', function() { | ||
var data = { | ||
criteria: [ | ||
{ | ||
op: "equal", | ||
path: [ | ||
"category" | ||
], | ||
value: "let's have a ball" | ||
}, | ||
{ | ||
op: "match", | ||
path: [ | ||
"question" | ||
], | ||
value: "scratched" | ||
}, | ||
{ | ||
op: "match", | ||
path: [ | ||
"question" | ||
], | ||
value: "sink" | ||
} | ||
], | ||
data: { | ||
response: "cue ball" | ||
} | ||
}; | ||
// before(function(){ | ||
// core = require('../../lib/core/index.js')(config.core); | ||
// }); | ||
describe('Router', function() { | ||
var createdId; | ||
// it.skip('rejects an invalid POST'); | ||
// it.skip('accepts a valid POST'); | ||
before(function(){ | ||
var app = require('express')(); | ||
core = require('../../lib/core/index.js')(config.core); | ||
app.use(core.router).use(function(err, req, res, next){}); | ||
request = require('supertest')(app); | ||
}); | ||
// it.skip('rejects an invalid PUT'); | ||
// it.skip('accepts a valid PUT'); | ||
after(function(done){ | ||
core.$arrdb.stop() | ||
.then(function(){ done(); }) | ||
.catch(done); | ||
}); | ||
// it.skip('responds to a GET with :id'); | ||
it('rejects an invalid POST', function(done){ | ||
request | ||
.post('/') | ||
.send({ | ||
foo: 'bar' | ||
}) | ||
.expect(400) | ||
.end(done); | ||
}); | ||
// it.skip('responds to a GET query with conditions'); | ||
// it.skip('responds to a GET query with a clue'); | ||
// it.skip('responds to a GET query with a clue and conditions'); | ||
it('accepts a valid POST', function(done){ | ||
request | ||
.post('/') | ||
.send(data) | ||
.expect(201) | ||
.end(function(err, res){ | ||
if(err) return done(err); | ||
assert.isString(res.body.id); | ||
createdId = res.body.id; | ||
delete res.body.id; | ||
assert.deepEqual(res.body, data); | ||
done(); | ||
}); | ||
}); | ||
// it.skip('accepts a valid DELETE'); | ||
it('rejects an invalid PUT', function(done){ | ||
request | ||
.put('/' + createdId) | ||
.send({ | ||
foo: 'bar' | ||
}) | ||
.expect(400) | ||
.end(done); | ||
}); | ||
it('accepts a valid PUT', function(done){ | ||
data.data.updated = 'updated'; | ||
request | ||
.put('/' + createdId) | ||
.send(data) | ||
.expect(200) | ||
.end(function(err, res){ | ||
if(err) return done(err); | ||
assert.equal(res.body.id, createdId); | ||
delete res.body.id; | ||
assert.deepEqual(res.body, data); | ||
done(); | ||
}); | ||
}); | ||
it('responds 404 to a nonexistant GET', function(done){ | ||
request | ||
.get('/nonexistant') | ||
.send(data) | ||
.expect(404) | ||
.end(done); | ||
}); | ||
it('responds 200 to an existant GET', function(done){ | ||
request | ||
.get('/' + createdId) | ||
.send(data) | ||
.expect(200) | ||
.end(function(err, res){ | ||
if(err) return done(err); | ||
assert.equal(res.body.id, createdId); | ||
delete res.body.id; | ||
assert.deepEqual(res.body, data); | ||
done(); | ||
}); | ||
}); | ||
it('responds to a GET query with criteria', function(done){ | ||
request | ||
.get('/') | ||
.query({criteria: '[{"op":"eq","path":["id"],"value":"'+createdId+'"}]'}) | ||
.send(data) | ||
.expect(200) | ||
.end(function(err, res){ | ||
if(err) return done(err); | ||
assert.isArray(res.body); | ||
assert.lengthOf(res.body, 1); | ||
done(); | ||
}); | ||
}); | ||
it('responds to a GET query with a clue', function(done){ | ||
request | ||
.get('/') | ||
.query({clue: '{"category": "let\'s have a ball", "question": "sink it and you\\\"ve scratched"}'}) | ||
.send(data) | ||
.expect(200) | ||
.end(function(err, res){ | ||
if(err) return done(err); | ||
assert.isArray(res.body); | ||
assert.lengthOf(res.body, 2); | ||
done(); | ||
}); | ||
}); | ||
it('responds 404 to a nonexistant DELETE', function(done){ | ||
request | ||
.delete('/nonexistant') | ||
.send(data) | ||
.expect(404) | ||
.end(done); | ||
}); | ||
it('responds 200 to an existant DELETE', function(done){ | ||
request | ||
.delete('/' + createdId) | ||
.send(data) | ||
.expect(200) | ||
.end(function(err, res){ | ||
if(err) return done(err); | ||
assert.equal(res.body.id, createdId); | ||
delete res.body.id; | ||
assert.deepEqual(res.body, data); | ||
done(); | ||
}); | ||
}); | ||
// }); | ||
}); |
61082
1342
4