Nutmeg Pumpkin Macchiato

    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)


    Install

    npm i rest-lib

    DownloadsWeekly Downloads

    0

    Version

    1.3.0

    License

    Apache-2.0

    Unpacked Size

    92.2 kB

    Total Files

    58

    Last publish

    Collaborators

    • nanlabs