Neverending Puppy Marathon

    restify-model

    0.3.2 • Public • Published

    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

    npm install restify-model

    Example Usage

    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

    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

    [{
      "name": "Tim",
      "occupation": "Enchanter",
      "id": 1
    }, {
      "name": "Roger",
      "occupation": "Shrubber",
      "id": 2
    }]

    GET /people/1

    {
      "name": "Tim",
      "occupation": "Enchanter",
      "id": 1
    }

    POST { name: 'Brave Sir Robin', occupation: 'Knight', id: 3 } /people

    {
      "name": "Brave Sir Robin",
      "occupation": "Knight",
      "id": 3
    }

    GET /people

    [{
      "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

    {
      "name": "Brave Sir Robin",
      "occupation": "Knight of the Round Table",
      "id": 3
    }

    Specifying CRUD Operations

    // CREATE, READ, UPDATE
    var CRUModel = Model.extend({
      operations: 'CRU'
    });

    Using a Database/Persistence Adapter

    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

    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.

    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

    var Persist = Person.extend({
      middleware: Person.middleware.extend({
        // Setting persist to true will load() on every request
        persist: true
      })
    });

    Customizing Routes

    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)

    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

    // 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');
    });

    Install

    npm i restify-model

    DownloadsWeekly Downloads

    2

    Version

    0.3.2

    License

    MIT

    Last publish

    Collaborators

    • baseprime