rest-lib

1.3.0 • Public • Published

Rest-lib

Rest-lib is a light-weight framework for building ReSTful APIs


Installation

$ npm install rest-lib

Quick start

const ioc = require('nan-ioc');
const restlib = require('rest-lib');

class Application {

  onInitialized() {
    this.expressServer
      .run()
      .then(() => console.log("Server running"));
  }
}

class HelloController {

  list() {
    return "Hello world";
  }

}

ioc.module([restlib.core])
  .controller('helloController', {
    'class': HelloController,
    'context': '/hello'
  })
  .component('application', {
    class: Application,
    expressServer: ioc.ref('expressServer')
  })
  .build({
    logger: {
      level: 'INFO'
    }
  });

Start the app:

  node .

Make a request:

  curl localhost:3000/hello

Application

To start off you will need to define an Application.js and an index.js

var Q = require('q');
module.exports = App;

App.prototype.onInitialized = function(){
  var bootstrap = [this.syncDb];
  boostrap.push(this.expressServer.run.bind(this,expressServer));
  bootstrap.reduce(Q.when, Q(true));
}

App.prototype.syncDb = function(){
  return this.dataSource.sync();
};

Defining modules

A module is a group of components with related behavior. You can define a module adding an index file to it like:

var ioc = require('nan-ioc');
var Service = require('Service');
var Controller = require('Controller');
var DBModel = require('DBModel');

ioc.module('myModule')
  .service('service',{
    class: Service
  })
  .controller('controller',{
    context: '/hello',
    class: Controller,
    service: ioc.ref('service')
  })
  .model('dbModel',{
    class: DBModel
  });

Note: You can have several of each (as long as they have a different definition name), you can reuse your components

A module can have:

Controllers

The methods that you can define on a controller to route through XHR requests are:

  • List: Method GET
  • Get: Method GET with an ID "/context/:id"

Note: you don't need to define the id, rest-lib will read it automaticly, you can access it from the request object that your method receives

  • Delete: Method DELETE
  • Create: Method POST
  • Update: Method PUT
module.exports = HelloController;
var i = 0;
function HelloController() {
}

HelloController.prototype.list = function (command) {
  return {
    'message': this.message + ' ' +  command.name
  };
};

HelloController.prototype.create = function (command) {
  return this.helloService.create(command);
};

For example, for the user context you can have:

  • GET /user -> Lists users
  • GET /user/:id -> Get a user
  • DELETE /user/:id -> Delete a user
  • CREATE /user -> Create a user
  • UPDATE /user/:id -> Update a user

Sometimes, you need add a nested routes. For example, with posts and comments you need a endpoint that returns all the comments of one post. So, you may define adding in the index file of your module:

ioc.module('myModule')
  .controller('postController',{
    context: '/post',
    routes: {
    posts: {
        verb: 'get',
        route: ':postId/comment'
        }
    },
    class: PostController
  });

The code above will generate 'GET /post/:postId/comment' and you need to define a comments method in your post controller.

Also, you can need define a set of methods for the nested routes. For example, following the post and comment context:

  • GET /post/:postId/comment -> Lists the comments for one post
  • GET /post/:postId/comment/:id -> Get a comment for one post
  • DELETE /post/:postId/comment/:id -> Delete a comment for one post
  • CREATE /post/:postId/comment -> Create a comment for a post
  • UPDATE /post/:postId/comment/:id -> Update a comment for one post

So, you can use the index file of the comment module and put the following code:

ioc.module('myModule')
  .controller('commentController',{
    context: '/post/:postId/comment',
    },
    class: CommentController
  });

Validators

There are four differents ways of define params in the validators:

  • Query: Params passed by the Url(/post?MY_PARAM=1)
  • Params: Params that are part of the Url. Most commonly between entities(post/:postId/comment/:id)
  • Body: This params are for the POST or PUT methods.
  • Header: For example, validate the content-type of the request.

When you define the validator you can specify what type of params you must receive in the controller:

var Joi = require('joi');
module.exports = {

  'update': {
    params: {
      id: Joi.number().required()
    },

    body: {
      name: Joi.string().required()
    }
  },

  'list': {
    query: {
      name: Joi.string().required()
    }
  },

  'create': {
    body: {
      name: Joi.string().required()
    }
  }
};

Note: If you define a validator for a controller, the methods validated will receive a Command object before the Request and Response objects, in this example the list method would receive an object like:

 {
   name: 'Jon'
 }

Services

var transactional = require('../').transactional;
module.exports = HelloService;

function HelloService(){
}

HelloService.prototype.create = transactional({inherit: true, isolationLevel: 'READ COMMITTED'}, function(project){
  return this.model.create(project)
});

Middlewares

var jwt = require('jsonwebtoken');
module.exports = class SessionMiddleware{
  get(){
    return function(request, response, next){
      var user = request.get('user');
      this.userService.verifyUser(user).then(function(){
        next();
      }).catch(next);
    }.bind(this);
  }
}

Database models

var Sequelize = require('sequelize');
module.exports = {

  modelName: 'Project',

  attributes: {
    name: {
      type: Sequelize.STRING
    }
  },

  afterDefined: function(models){
    this.belongsToMany(models.User, {through: 'users_project'});
  }
};

Mixins

By default, rest-lib includes a set of mixins for your middlewares, services and controllers. For example, all controller methods throw a not implemented (501) error instead of a 404.


Config

You can set up a json file for your settings and add them to the index build, as seen in the example index.js file.

If an authentication field is found, rest-lib will add the express-jwt middleware to verify the requests. If you want your route to not be protected you need to add it in an array in the unsecuredUris field, like:

authentication: {
  unsecuredUris: ['/auth']
}

Note: You will still need to sign your own tokens


Database

You can set up a connection using Sequelize as seen in the example,

var ioc = require('nan-ioc');
var UserModel = require('./User');
var ProjectModel = require('./Project');
var App = require('./App');


ioc.module(['../lib/model'])
  .model('User', {
    'class': UserModel
  })
  .model('Project', {
    'class': ProjectModel
  })
  .component('app',{
    'class': App,
    'env': '${env}',
    'dataSource': ioc.ref('dataSource'),
    'Project': ioc.ref('Project'),
    'User': ioc.ref('User')
  })
  .build({
    env: 'dev',
    server:{
      port: 9000
    },
    db:{
      database: 'restlib',
      username: 'restlib',
      password: 'restlib',
      sync: {force: true},//see http://docs.sequelizejs.com/en/latest/api/sequelize/#syncoptions-promise
      options: {
        host: 'localhost',
        port: '3306',
        logging: console.log
      }
    }
});

Note: You need to inject dataSource into your Application, you can also do this directly on the Application definition (main index.js file)


Package Sidebar

Install

npm i rest-lib

Weekly Downloads

0

Version

1.3.0

License

Apache-2.0

Unpacked Size

92.2 kB

Total Files

58

Last publish

Collaborators

  • ulises-jeremias
  • nanlabs1