UNPKG

restify-model

Version:

'A surprisingly useful model/collection adapter that builds routes and handles CRUD operations (Create, Read, Update and Delete). Works with any custom database adapter (Postgres, MySQL, MongoDB, etc.).'

334 lines (294 loc) 6.97 kB
## Restify Model A surprisingly useful model/collection adapter that builds routes and handles CRUD operations (Create, Read, Update and Delete). Works with any custom database adapter (Postgres, MySQL, MongoDB, etc.). ### Installation ```bash npm install restify-model ``` ### Example Usage ```javascript var restify = require('restify'); var server = restify.createServer(); var Model = require('restify-model')(server); var Person = Model.extend({ // GET, POST to /people // GET, PUT, DELETE to /people/:id path: '/people', defaults: { name: 'Arthur', occupation: 'King' } }); var tim = new Person({ name: 'Tim', occupation: 'Enchanter', id: 1 }); var roger = new Person({ name: 'Roger', occupation: 'Shrubber', id: 2 }); Person.add([tim, roger]); // GET /people // => [{ // "name": "Tim", // "occupation": "Enchanter", // "id": 1 // }, { // "name": "Roger", // "occupation": "Shrubber", // "id": 2 // }] server.listen(3000); ``` ### Nested Routes & Collection Relationships ```javascript var Equipment = Model.extend({ key: Person.relationship('carrying'), path: Person.namespace('/equipment'), defaults: { name: 'Sword' } }); Equipment.add({ name: 'Coconuts', id: 1 }); Person.add({ id: 4, name: 'Patsy', carrying: Equipment.with(function(model) { return model.get('name') === 'Coconuts'; }).pluck('id') }); // GET, POST to /people/:person_id/equipment // GET, PUT, DELETE to /people/:person_id/equipment/:id ``` ### CRUD Operations `GET` `/people` ```javascript [{ "name": "Tim", "occupation": "Enchanter", "id": 1 }, { "name": "Roger", "occupation": "Shrubber", "id": 2 }] ``` `GET` `/people/1` ```javascript { "name": "Tim", "occupation": "Enchanter", "id": 1 } ``` `POST` `{ name: 'Brave Sir Robin', occupation: 'Knight', id: 3 }` `/people` ```javascript { "name": "Brave Sir Robin", "occupation": "Knight", "id": 3 } ``` `GET` `/people` ```javascript [{ "name": "Tim", "occupation": "Enchanter", "id": 1 }, { "name": "Roger", "occupation": "Shrubber", "id": 2 }, { "name": "Brave Sir Robin", "occupation": "Knight", "id": 3 }] ``` `PUT` `{ name: 'Brave Sir Robin', occupation: 'Knight of the Round Table' }` `/people/3` ```javascript { "name": "Brave Sir Robin", "occupation": "Knight of the Round Table", "id": 3 } ``` ### Specifying CRUD Operations ```javascript // CREATE, READ, UPDATE var CRUModel = Model.extend({ operations: 'CRU' }); ``` ### Using a Database/Persistence Adapter ```javascript var MyModel = Model.extend({ unique_key: 'id', adapter: function() { var self = this; return { read: function(list) { // Get All records list([]); }, create: function(model) { // A new model was created console.log('Created', model.id()); }, update: function(model) { // Model was updated console.log('Updated', model.id()); }, remove: function(model) { // Model was deleted console.log('Removed', model.id()); } } } }); var Enchanter = MyModel.extend({ defaults: { occupation: 'Enchanter' } }); var tim = new Enchanter({ id: 1 }); tim.save(); // => Created 1 ``` ### Middleware Restify Model comes with the following middleware - `findById` Finds related model, assigns it to `req.model`, calls `next()` - `detail` Gets `req.model` and sends `model.toJSON()`, ends request - `list` Gets `req.collection` and sends `collection.toJSON()`, ends request - `create` Creates a new instance, assigns it to `req.model` and calls `model.save()`, calls `next()` (`middleware.detail`) - `update` Updates `req.model` with body and calls `model.save()`, calls `next()` (`middleware.detail`) - `remove` Removes `req.model`, calls `next()` (`middleware.detail`) ### Customizing middleware ```javascript var CustomModel = Model.extend({ middleware: Model.middleware.extend({ list: function(req, res) { res.send(CustomModel.all()); } }) }); ``` ### Sample Database Adapter This is an example of a simple database adapter. Any database ORM can be used here (Postgres, MySQL, MongoDB, etc.). Pseudo coding MongoDB as an example. ```javascript var mongoose = require('mongoose').connect(); var DBModel = Model.extend({ unique_key: '_id', adapter: function() { var self = this; var schema = this.schema; if (!schema) { return false; } return { read: function(cb) { schema.getAll(function(err, docs) { cb(docs.toObject()); }); }, create: function(model) { schema.create(model.attributes, function(err, row) { model.set('id', row._inserted_id); }); }, update: function(model) { schema.update(model.id(), model.changes); }, remove: function(model) { schema.remove(model.id()); } } }, }); var Person = DBModel.extend({ schema: mongoose.Person, path: '/people', defaults: { name: 'Old Man from Scene 24', occupation: 'Peasant' } }); var tim = new Person({ name: 'Tim', occupation: 'Enchanter' }); tim.save(); // => Created 54b9e08ed983b41d432473e4 // POST /people { name: 'Roger', occupation: 'Shrubber' } // => Created 54bcacb4c812ec812382b6b2 // GET /people // => [{ // "name": "Tim", // "occupation": "Enchanter", // "_id": "54b9e08ed983b41d432473e4" // }, { // "name": "Roger", // "occupation": "Shrubber", // "_id": "54bcacb4c812ec812382b6b2" // }] ``` ### Running `collection.load()` on every request ```javascript var Persist = Person.extend({ middleware: Person.middleware.extend({ // Setting persist to true will load() on every request persist: true }) }); ``` ### Customizing Routes ```javascript var Custom = Model.extend({ path: '/', routes: { "/foo": function(req, res, next) { // Do stuff }, "/bar": function(req, res, next) { // Do stuff } } }); ``` ### Model as an Action (and disabling CRUD) ```javascript var Action = Model.extend({ // Setting service to false disables CRUD operations on /people/add service: false, // GET /people/add path: Person.namespace('/add') }); ``` ### Even more middleware functionality ```javascript // You can specify which middleware to run on a specific namespace function doAuth(req, res, next) { if (req.model.isAuthorized()) { next(); } else { res.send(401); } } function doSomethingElse(req, res, next) { somethingElse(); next(); } var customNamespace = Person.namespace('/auth', doAuth, doSomethingElse); var CustomModel = Model.extend({ // GET /person/auth will run the middleware above path: customNamespace }); // Or you can explicitly call namespace method (get, put, post, delete, etc) // GET /person/:id/foo customNamespace.get('/foo', function(req, res, next) { res.send('bar'); }); ```