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

rest-lib

v1.3.0

Published

REST library

Downloads

4

Readme

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](## Application) 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)