0.0.2 • Published 9 years ago

osh-model v0.0.2

Weekly downloads
1
License
MIT
Repository
-
Last release
9 years ago

Model

A very simple starting point for public model definitions in an isomorphic Node.js web app or API. Its few features include

  • a model validation system and
  • an event system that makes sure all model attributes are being handled by the developer.

Check out the source; it's short.

Installation

npm install osh-model

Background

You would like to define your models once and reuse code for client-side and server-side validation. Also, separating model definitions from storage seems like a nice way to abstract your storage technique (i.e. which database software you use) in case you want to change later.

This library helps isolate your backend changes from your public interface agreement and helps with development by enforcing handling of all model attributes. It makes a single assumption about your storage techniques: they exist.

Usage

Model definition (let's call it user.js):

var Model = require('osh-model');

var User = new Model({
  username: {
    validate: function(username) {
      if (!/^[a-z]$/.test(username)) return 'Use a-z.';
    },
    required: true
  },

  password: {
    validate: function(password) {
      if (password.length < 4) return 'That a short password!';
    },
    required: true
  }
});

module.exports = User;

Server-side usage:

var User = require('./user');
var bcrypt = require('bcrypt');

User.keep('username');

User.on('password', function(password, user, done) {
  bcrypt.hash(password, 8, function(err, hash) {
    user.pwhash = hash;
    done(err);
  });
});

// Throws if you forgot to listen for an attribute. Yay.
User.check();

app.post('/users', function(req, res, next) {
  User.create(req.body, function(err, user) {
    if (err) return next(err);

    // Persist here; user is validated.

    res.send({
      message: 'ok',
      result: user
    });
  });
});

In the browser:

var User = require('./user');

var input = document.getElementById('password');
input.onchange = function(ev) {
  var msg = User.validate('password', ev.target.value);
  if (msg) {
    // Add message to the document next to the password input.
  }
  else {
    // Remove any messages.
  }
};

Documentation

In the browser, a Model is just a validator. Use it to check the values of form inputs before querying your API. Nuff said.

On the server, a Model is an augmented EventEmitter. It emits an event (named by attribute) whenever a model is created or updated.

Model.on(attr, callback)

Listen for the creation of the indicated attribute. This is fired whenever the attribute is encountered on a call to Model.create or Model.update.

The callback takes 3 arguments:

callback(value, model, done)

where value is the value of the validated attribute, model is a POJO namespace, and done is a function that must be called when finished operating on the attribute.

The model namespace is for passing along processed attributes to the callbacks on Model.create and Model.update.

Model.on('create', callback)

Called immediately after Model.create() (before attribute validation) so that the model namespace can be prepared. For example, for denormalization:

Article.on('create', function(article) {
  article.byAuthor = {};
  article.byId = {};
});

Notice there is no done callback given here; the listener is assumed synchronous.

Model.on('update', callback)

See documentation for Model.on('create').

Model.keep(attr)

Equivalent to, e.g.:

User.on('username', function(username, user, done) {
  user.username = username;
  done();
});

but saves a function call. This is little more than recognition that the attribute exists and it should be taken as given (if validated).

Model.toss(attr)

Yeah, attr exists, we know and we don't care. Don't fail on Model.check().

Model.check()

Call this after setting all attribute listeners. If one is missing, it will throw an error.

Model.create(model, callback)

Call this on the server when you want to create an instance of the model. This function simply validates the attributes of model (and makes sure they exist, if required) and fires the attribute events. In an Express app, you will probably pass req.body directly as model.

The callback provides an error in the first slot, and the validated model in the second.

callback(err, model)

Here, model is not the same object passed to Model.create(); rather, it is the namespace passed to each attribute callback.

Model.update(model, callback)

The only difference between this and Model.create, is that this version validates (and fires the events for) only those attributes defined on the given model instance, whereas Model.create validates all attributes on the Model definition.

License

MIT

0.0.2

9 years ago

0.0.1

9 years ago

0.0.0

9 years ago