# IWinter 一个路由转控制器的 Nodejs 库
[![npm version](https://badge.fury.io/js/iwinter.svg)](https://badge.fury.io/js/iwinter)
[![NPM downloads](http://img.shields.io/npm/dy/iwinter.svg?style=flat)](https://www.npmjs.com/package/iwinter)

> A restful router -> controller library for node.<br>

IWinter 为了让使用者以更优雅的姿势进行路由的编写。名称的由来：
>The winter is coming !

以前需要这样编写路由 :(
```
//app.js
...
let users = require('./routes/users');
let orders = require('./routes/orders');

app.use('/api/users', users);
app.use('/api/orders', orders);
...

//routers/orders.js
...
router.route('/')
    .get(function (req, res, next) {
        let {page, timeRange, customerId, orderNumber} = req.query;
        let limit = constants.PAGE_SIZE;
        let skip = (page - 1) * limit;
        let currentUser = global[Symbol.for('currentUser')];
		let queryCondition = {
			userId: currentUser['_id']
		};
        ...
```
使用 iwinter 之后可以更优雅的编写路由 :)
```
import {Controller, Path, GET, POST, PathParam, BodyParam} from 'iwinter';

@Path('/api/orders')
class OrdersController extends Controller {

    @GET
    @Path('/:name/:id', (ctx, next)=> ~~ctx.params.id > 20)
    getAllOrders(@PathParam('id') id: number, @PathParam('name') name: string){
        return [{
            id: id, name, content: 'test', author: 'test', comments: []
        }];
    }

    @POST
    @Path('/add')
    addPost(@BodyParam('order') order: object){
        return order;
    }
}

export default OrdersController;

```

### 谁适合使用 IWinter:
`*` Nodejs 用户<br>
`*` Typescript 用户<br>
`*` Express / Koa 用户<br>

========================================== ============================================== ==========================================

### IWinter 安装：
```
npm install --save iwinter
```

### IWinter 引入：
```
import IWinter from 'iwinter';
OR
const IWinter = require('iwinter');
```

### Koa 中如何使用：
```
import * as Router from 'koa-router';
...
app.use(new IWinter({
    engine: 'koa',
    router: new Router(),
    dir: path.join(__dirname, 'controller')
}).controller());
...
```

### Express 中如何使用：
1`.` 路由挂载到app上<br>
```
import * as express from 'express';
let app = express();
let router = express.Router();
...
new IWinter({
    engine: 'express',
    router: app,
    dir: path.join(__dirname, 'controller'),
    prefix: ''
}).controller();
```
2`.` 以中间件的形式使用<br>
```
app.use(new IWinter({
    engine: 'express',
    router: router,
    dir: path.join(__dirname, 'controller'),
    prefix: ''
}).controller());
```

### 构造函数参数配置说明(options: {})
```
new IWinter({
    engine: 'express',
    router: router,
    dir: path.join(__dirname, 'controller'),
    prefix: ''
})
```
1`.` engine 使用的环境类型，可选项 'express | koa', 必需<br>
2`.` router 路由对象，配置参照 (Koa 中如何使用 | Express 中如何使用)，必需<br>
3`.` dir 控制器文件路径，必需<br>
4`.` 网关统一前缀，例如 '/api'，非必需<br>

### API

1`.` 支持路径装饰器 `Path`。<br>
`Path` 是一个装饰器工厂函数，接收两个参数: `@Path(path: string, permission?: Function)`, <br>
`permission` 为权限拦截函数，其参数为原始请求参数 Express: (req, req, next) | Koa: (ctx, next)，用于权限验证，返回值： `true`->验证成功；`false`->验证失败。<br>
可以进行控制器级别及路径级别的权限验证。<br>

2`.` 支持 `GET POST PUT DELETE` 方法，可使用装饰器 `@GET @POST @PUT @DELETE`<br>

3`.` 支持获取路径参数、查询参数、post请求体及原始请求对象 ` PathParam, QueryParam, BodyParam, ReqParam, ResParam, CtxParam, NextParam, OriginParam `。<br>

Express | Koa 中使用 `@PathParam` 获取路径参数, `@QueryParam` 获取查询参数, `@BodyParam` 获取请求体数据 ;<br>

Express 环境中使用 `@ReqParam, @ResParam, @NextParam` 可以用于分别获取原始参数，也可通过 `@OriginParam` 获取原始参数对象 `{req, res, next}`;<br>

Koa 环境中使用 `@CtxParam, @NextParam` 可以分别用于获取原始参数，也可通过 `@OriginParam` 获取原始参数对象 `{ctx, next}`.
之所以暴露原始请求对象是为了方便进行一些自由度更大的操作，例如重定向等。

4`.` 支持 `Before, After` 方法，可以对路由处理函数进行切面编程，其参数为原始请求参数 Express: (req, req, next) | Koa: (ctx, next)，可在请求处理的前置和后置进行业务逻辑处理。<br>

### Changelog
当前最新版本为 1.1.0

#### 1.1.0
增加可以对路由处理函数进行切面编程的钩子函数 `Before、After`，</br>
可以在路由处理的前后进行相应的业务处理操作。</br>

#### 1.0.2
重大改变，增加 Controller 基类，所有的控制器类都需要继承该类：</br>
增加 Controller 基类是为了更加严谨的对控制器类进行判断。</br>

#### 0.5.2
修复 IWinterController(控制器类) 方法内 this 指向的问题：</br>
在 0.5.1 版本中， IWinterController 内的方法的 this 指向 path.ts 文件的 exports 对象，在 0.5.2 版本对该问题进行了修复，IWinterController 方法的 this 指向 IWinterController 实例对象。</br>

#### 0.5.1
修复了 IWinterController(控制器类) 根路径的bug：</br>
在0.5.0版本中，如果 IWinterController 没有装饰器 @Path(path: string) 会导致路由装载错误，
0.5.1版本中修复该问题。</br>

#### 0.5.0
iwinter 第一个发布版本。

### 从 0.5.2 升级到 1.0.2
从 0.5.2 升级到 1.0.2 版本，只需要做以下改变：</br>
```
import {Controller} from 'iwinter';
class PostController extends Controller {

}
```
恭喜你！升级完成 :)

### 示例项目
[recatch-service](https://github.com/yvanwangl/recatch-service) recatch 项目的后端服务，全面使用 iwinter

### 使用示例
```
import {Controller, Path, GET, POST, PathParam, BodyParam, CtxParam, NextParam, OriginParam, Before, After} from 'iwinter';
import {PostModel} from '../models/PostModel';
import {auth} from '../auth';

@Path('/api/posts', auth)
class PostController extends Controller {

    @GET
    @Path('/:name/:id', (ctx, next)=> ~~ctx.params.id > 20)	//Path(path:string, permission: Function)
    @Before((ctx, next) => ctx.beforeHook = 'before')
    @After((ctx, next) => console.log('done'))
    getAllPosts(@PathParam('id') id: number, @PathParam('name') name: string, @CtxParam('ctx') ctx: any){
        //ctx.response.redirect('/users');
        return [{
            id: id, name, content: 'test', author: 'test', comments: []
        }];
    }

    @POST
    @Path('/add')
    async addPost(@BodyParam('post') post: object){
    	let newPost = new Post(post);
        let result = await newPost.save();
        return result;
    }
}

export default PostController;
```
在 Express 中 `getAllPosts` 方法需要返回一个立即值 或 Promise 对象；<br>
在 Koa 中 `getAllPosts` 方法可以使用 `async/await`。<br>

[Express 示例](https://github.com/yvanwangl/iwinter/tree/master/examples/express-example)<br>
[Koa 示例](https://github.com/yvanwangl/iwinter/tree/master/examples/koa-example)<br>

项目会不断完善，如果有问题欢迎提 Issues

>欢迎Star :)



