npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

osh-model

v0.0.2

Published

openscihub.org: basic isomorphic model definition

Downloads

4

Readme

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