rest-lib
v1.3.0
Published
REST library
Downloads
3
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)