Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

使用decorator处理model层验证 #8

Open
jiangtao opened this issue Sep 13, 2017 · 0 comments
Open

使用decorator处理model层验证 #8

jiangtao opened this issue Sep 13, 2017 · 0 comments
Labels

Comments

@jiangtao
Copy link
Owner

最近开始写一些node的东西,以前使用thinkjs这种高度集成的框架,对我这种懒人来说太方便。但经过统计调查发现大伙对koa, express等比较青睐。于是俺也“弃恶从善”, 当然thinkjs也是非常好的应用框架。本博客的使用的就是thinkjs开发的firekylin系统。 回到正题:在使用koa封装处理数据验证的时候,发现以往的做法是错的,或者是很冗余的。

验证数据的几种方式

路由层验证

在路由层,直接在路由层做scheme校验;每个路由表维护对应的scheme,工作量也不小。

controller层验证

controller层, 直接写各种分支判断 。缺点:同样数据或者字段校验需要在不同的controller之间添加 代码校验,冗余代码过多

model层验证

model层做校验,以往的写法直接在里面做校验 或 用 mongoose等做校验,但这种校验无法对复杂校验起作用。比如产品经理要验证 邮箱,电话,密码等等。要知道在某些厂特殊需求,规则复杂,当然数据库的数据也要符合规则,减少不必要的清理。 那直接写在model里面校验怎么样? 要知道老板和产品经理的思维变化很快,而model层那么关键和重要,这种侵入式的方式,耦合太强,牵一发而动全身。

使用decorators做验证

那么, 有木有好的方式?

最近和同事调研发现,javapython@, 也就是 修饰器。作用就是对方法进行修改返回新的方法, 听起来是不是很熟悉,木有错,就是高阶函数(higher order function). JavaScriptES7中支持decoratorsbabel是我们更好的使用这些特性。具体实现原理可查看这里

javascript实现一个decorator

export function validate(vKey, message, validator) {
    return (target, key, descriptor) => {
        // descriptor中的属性,通过Object.defineProperty定义
        const { set, get, value, writable, configurable, writable, enumerable} = descriptor
        // 重写 descriptor
        return descriptor
    }
}

预期验证效果

由于Javascript中的decorators支持在类(class)中使用,不支持类之外的方法使用。因此期望代码是这样的。

class Model{
    constructor(){
        
    }
    @validate('name', 'name is not a chinese name', validator.isChineseName)
    @validate('age', 'age is out of [0, 100]', validator.isValidAge)
    @validate('email', 'email is invalid email', validator.isEmail)
    insert(obj){
        // db insert with obj.
    }
    
    @validate('name', 'name is not a chinese name', validator.isChineseName)
    @validate('age', 'age is out of [0, 100]', validator.isValidAge)
    @validate('email', 'email is invalid email', validator.isEmail)
    update(obj){
        // db update with obj.
    }
}

预期结果发现上面的 validate 有大量的重复,利用gettersetter改进一下:

class Model{
    constructor(){
       this._scheme = null 
    }
    
    @validate('name', 'name is not a chinese name', validator.isChineseName)
    @validate('age', 'age is out of [0, 100]', validator.isValidAge)
    @validate('email', 'email is invalid email', validator.isEmail)
    set scheme(v){
        this._scheme  = v
    }
    get scheme(){
        return this._scheme
    }
    
    insert(){
        // db insert this.scheme.
    }
    
    update(){
        // db update this.scheme.
    }
}

因此需要实现一个验证 setter的 decorators. 在这之前讨论下 setter decorators validate对外接口(验证字段错误处理)

验证字段错误处理

  • throw Error的形式

对外每次构建实例之后,对scheme设置时需要try catch才能拿到错误信息

  • 统一格式处理
    需要对对外暴露的字段做一次校验。

基于每个模块各司其职,Model层在Model层做处理,当不符合规则时候,返回统一格式给API层。

最终期望的结果:

class Model {
    constructor(ctx, dbname) {
        this.table = ctx.mongo.collection(dbname)
        this._scheme = null
    }

    @validate('name', 'name is not a chinese name', validator.isChineseName)
    @validate('age', 'age is out of [0, 100]', validator.isValidAge)
    @validate('email', 'email is invalid email', validator.isEmail)
    set scheme(v) {
        this._scheme = v
    }
    get scheme() {
        return this._scheme
    }

    insert() {
        // 将验证错误信息方法在scheme中
        if(this.scheme.validateResult && this.scheme.validateResult.invalid){
            return this.scheme.validateResult
        } else {
            delete this.scheme.validateResult
            // 执行db插入操作.
        }
    }

    update() {
        // 将验证错误信息方法在scheme中
        if(this.scheme.validateResult && this.scheme.validateResult.invalid){
            return this.scheme.validateResult
        } else {
            delete this.scheme.validateResult
            // 执行db更新操作.
        }
    }
}

坑点

  • generator不支持 decorator
  • setter实现decorator, 需要自行处理异常拦截的问题

参考资料

以上是使用decorators实现model验证的思路和过程,查看validate decorator实现
decorator给开发带来了很好的集中式处理

如有不妥,欢迎指正。转载请写明出处。

转载请备注出处

@jiangtao jiangtao added the ES6 label Sep 13, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant