vern-core

Community version. VERN is the virtual elastic resource node. The new method for creating applications. Built on a Mongo/Restify/AngularJS/LESS Stack.

#Copyright Notice

Vern is copyright 2015 uh-sem-blee, Co. Built by typefoo.

Vern -- at its core -- is a powerful API builder utilizing a Model -> Controller interface. It is meant to scaffold and scale easily from small projects to enterprise clusters.

The best method for utilizing Vern is by using the vern-cli module to create a full-stack boilerplate for your project.

However, if you're interested in using Vern as a low level API builder, please continue reading.

npm install vern-core

Contributing to vern-core can be done via your own forked repository

git clone <your-forked-repo-url>
  • Add the master source to your remote list for pulling updates easily
git remote add core git@github.com:uh-sem-blee/vern-core.git
  • When you need to update perform a git pull core master
  • Create issues with the following formats:
[feature] _component_name_ _short_description_
[documentation] _component_name_ _sub_component_name_
[bug] _component_name_ _short_description_
  • When committing ensure your messages correspond with your issue. This practice ensures commits are made with relevant information and can easily be tracked.
git commit -m "#_issue_number_ _component_name_ _description_of_commit_"
  • Once you believe your issue is resolved, perform a pull request from your forked repo page.
  • We will review your request and integrate the necessary pieces into core.

Vern consists of 2 main structures, Controllers & Models.

You can setup controllers with vern-core by doing the following:

var vern = require('vern-core');
 
new vern().then(function($vern) {
  $vern.loadControllers('./controllers'); // or /path/to/your/controller files 
  $vern.loadModels('./models'); // or /path/to/your/model/files 
}).fail(function(err) {
  console.log(err);
  console.log(err.stack);
  // you could have email or push notifications here. 
  // 
  // or exit 
  process.exit(1);
});

If you want to manually setup controllers do the following:

var vern = require('vern-core');
 
new vern().then(function($vern) {
  function MyController($vern) {
    var $scope = new $vern.controller();
 
    $scope.handleCustom = function(reqresnext) {
      // do something 
      // if you encounter an error, you can use the built-in error handler method: 
      // res.resp.handleError(500, new Error('Something went wrong')); 
      res.resp.data({hello: true}); // data to return 
      res.resp.send();
      return next();
    };
 
    $scope.addRoute({
      method: 'get',
      path: '/my_controller/custom_route',
      controller: $scope.handleCustom
    });
 
    return $scope;
  }
 
  function MyModel() {
    this.name = null;
    this.blob = '';
    this.image = null;
    this.num = 0;
    this.date = new Date();
    // enter more parameters here 
 
    return this.update(arguments[0]);
  }
 
  $vern.models.MyModel = new $vern.model().extend(MyModel, {
    collection: 'my_models',
    indexes: [], // set indexes for the DB collection 
    exclude: [], // exclude certain parameters from public output 
    validations: {}, // setup validations, see below 
    validation_exceptions: {}, // setup exceptions to validations 
    non_editable: [] // set parameters non-editable 
  }, null);
 
  $vern.controllers.my_controller = new MyController($vern).init({
    model: $vern.models.MyModel,
    publicRoute: '/my_controller',
    //publicPostRoute: '/homepage', 
    //publicDeleteRoute: '/homepage', 
  });
}).fail(function(err) {
  console.log(err);
  console.log(err.stack);
  // you could have email or push notifications here. 
  // 
  // or exit 
  process.exit(1);
});

These are the parameters you can alter in a controller:

$scope.model // The model to use
$scope.publicRoute // The public [GET] route path
$scope.publicPostRoute // The public [POST] route path
$scope.publicPutRoute // The public [PUT] route path
$scope.publicDeleteRoute // The public [DELETE] route path
$scope.version // Set a version for your controller api, default is '1.0.0'
$scope.routes // Best not to alter this, but it holds all the routing information generated by $scope.initRoutes();
$scope.initStack // Best not to alter this, but it holds all the middleware for this controller, utilize $scope.use() instead

These are the basic methods you can utilize inside a controller, we will cover advanced topics and methods later.

configOptions: (optional)

{
  model: ModelName, // the model you want to set for this controller
  publicRoute: '/path/to/get', // setup CRUD [GET] routing
  enablePublicPost: true, // setup CRUD [POST] routing, default false
  enablePublicPut: true, //setup CRUD [PUT] which is appended with '/:id',
  enablePublicDelete: false, // setup CRUD [DELETE]
  version: '1.0.0' // Set the version of the controller api
}

routeOptions:

{
  method: 'get', // optional, defaults to 'get'
  path: '/routing/path', set the routing path
  controller: $scope.myControllerForRoutingPath, // Set the controller method to be called. This should be a function with the following parameters: (req, res, next)
  version: '1.0.0', // optional, set a custom version for this method
}

Vern's boilerplate frontend, written in AngularJS, comes with a vern-angular-standard module which provides several directives and services to interact with the Vern API, and is the recommended way of connecting via web apps.

  • GET - Get methods expect certain query parameters, all of which are optional:
fields {String} A JSON String which is parsed into the fields to include or exclude (eg: {'a': true} or {'a': false}), if not provided it returns all.
skip {Number} `(defaults to 0)`
limit {Number} `(defaults to 10)`
sort {String|Object|Array} As a string, a field to sort by. As an object it represents a Mongo search. As an array it represents multiple fields to sort by
sortDir {Number|Array} As a number, -1 or 1 to determine the sort direction. As an array, the direction to sort the field in the `req.params.sort` array match.
conditions {String} A JSON string which is parsed into and object of key, value pairs
search {String} A JSON string which is parsed into and object of key, value pairs. The value of which is a regular expression
searchOptions {String} The regular expression options to be passed with all search parameters. eg: 'i' to ignore case
  • POST - Posting to a controller

Expects a JSON object posted to the controller. If you supply an _id it will try to update the object with that ID, or return a 404 error.

  • PUT - Updating a model in a controller

Expects a JSON object PUT to the controller route, will return an error if the _id is missing or invalid.

  • DELETE - Delete a model in a controller

Best used with vern-authentication to ensure data isn't deleted unless authorized. Send a JSON packet {_id: 'id_of_object'} representing the object to be deleted.

Let's dissect creating a model:

$vern.models.MyModel = new $vern.model().extend(MyModel, {
  collection: 'my_models',
  indexes: [], // set indexes for the DB collection
  exclude: [], // exclude certain parameters from public output
  validations: {}, // setup validations, see below
  validation_exceptions: {}, // setup exceptions to validations
  non_editable: [] // set parameters non-editable
}, null);

new $vern.model() - create a new BaseModel

.extend(MyModel, options, parentModel) - extend BaseModel functionality with the options and optional parentModel

  • validations

This is an object which lists parameters. Vern has a few built in validations and you can write custom validation functions as well. Here is an example and list of the built-in validations:

'checkPassword' - Will validate the parameter along with the parameter name appended with _confirm so you could have submitted a password parameter, along with a password_confirm parameter to be checked against.

'checkEmail' - Will validate the parameter is an email address.

'checkUsername' - Will validate the parameter is at least 3 characters in length.

'notEmpty' - Will validate the parameter is at least 1 character long.

'notNull' - Will validate the parameter is not null or it must exist.

'isCreditCard' - Will validate the parameter is a credit card number.

'isNumber' - Will validate the parameter is a number, or will return 0.

'isDate' - Will validate the parameter is a date or date string, or returns null.

Custom validation functions:

Here is an example of a custom validation for a date:

validations: {
  start_date: function(data, fields) {
    if(typeof data === 'string') {
      return new Date(data);
    }
 
    return data;
  }
}

All custom validation functions take 2 parameters, 'data' and 'fields' - where 'data' is the data being submitted, and 'fields' is all the other parameters submitted that you can compare against if needed.

  • validation_exceptions

You can setup validation exceptions for certain methods ('get', 'post', 'put', 'delete') like so:

validation_exceptions: {
  put: ['password']
}

In this example you want to avoid validating the 'password' parameter on PUT requests, which makes sense since you don't want to check for a password, and probably would want to also set password to non-editable which would prevent a standard CRUD method from allowing you to update a password. Another way around this is to utilize middleware to encode a password or check if a password is present in a request, and fill it in if it isn't.

When using a model inside a controller method, you have a subset of methods you can utilize.

Here's a quick example of a common usage of a model:

$scope.myController = function(reqresnext) {
  new $vern.models.MyModel().query({name: req.params.name}, function(errmodels) {
    if(err) {
      return res.resp.handleError(500, err);
    }
 
    var output = [];
    for(var i = 0; i < models.length; i++) {
      output.push(models[i].output()); // we want to do this because we may not want to return a raw model data, calling the .output() method on a model will parse any excluded parameters from output. 
    }
 
    res.resp.data(output);
    res.resp.send();
  });
};

model.output([override]) - Output a model object ready for consumption. Pass true as the override if you want to skip exclusions from your model config.

model.stub() - This is useful if you want to output a smaller version of your model. Useful when outputting large quantities of data, or overview information. The default stub() method just returns the _id, but you can override the stub method in your model creation like so:

MyModel.prototype.stub = function() {
  return {
    _id: this._id,
    name: this.name
  };
};

model.query(parameters, [options], callback) - Query the database for specific model parameters, optional options (an object which can contain things like {limit: 10, skip: 10, fields: ['name', 'blob'], sort: {'name', -1}}), and handle the callback which takes two variables, err (if any error occurs) and models (which will be an array of models).

model.queryRaw(options, callback) - A simpler version of query which sends any options you specify to the data collector.

model.getById(id, callback) - Query the database for a data item with specific ID. Will only return one result instead of an array.

model.count([parameters], callback) - Query the specific model collection for the number of entries that exist with optional parameters. The callback will have 2 variables, err and count (which is an integer).

model.sum(match, field, callback) - Query the model collection and return a sum for a parameters match on a specific field. The callback will have 2 variables, err and sum (which is a number).

model.save(callback) - One of the most important methods used for updating your models and saving to the database. The callback should be a function with 2 variables err and model which is an updated version of the model.

model.del(callback) - Delete a model entry from the database. Callback has 2 variables, err and confirm