使用node.js的对象模式验证模块joi引入强类型

  • 弱类型的Javascript

    Javascript是一门弱类型的语言,定义变量不需要指定类型,可以为同一个变量赋任意类型的值。误用类型不会报错,而结果会让你大吃一惊:

    > "1" + 1
    '11'
    > if ("false") { console.log("yes") } else { console.log("no"); }
    yes
    undefined
    > 
    

    redis中很多数据结构取出时都是字符串值(如:set、hash),调用方需要自行将它转换成正确的类型(如:Boolean、Date、Number),如果不转换成正确的类型会导致冗长的代码,如Boolean类型:

    if ((String(model.stoped) == 'true')) {
        // Do something when stoped.
    }
    

    如果手工转换成正确的类型肯定要写很多样板代码了。

  • 对象模式验证模块 joi

    有很多的ORM( Object Relational Mapping 对象关系映射)库都能够实现强类型的数据模型,但是它们都相当的复杂,支持各种各样的数据库后端,支持一对一、一对多、多对多等数据关系,但是很少支持分表分库,我们的系统一般是数据模型简单但要考虑用户量大了横向扩展,所以一开始就进行了分表分库,无法使用重型的ORM。

    如果有一个能够自动根据模式(Schema)定义对值进行类型转换的库,一定会非常有用。

    joi 一个Javascript对象模式描述语言以及验证(Object schema description language and validator for JavaScript objects)的库,它可以完成对象类型转换以及合法性验证。

  • joi 的用法示例

    var joi = require('joi');
    var redis = require('redis');
    
    var client = redis.createClient(6379, '127.0.0.1');
    
    var User = function (options) {
        if (! options) {
            options = {};
        }
    
        this.id = options.id || 0;
        this.name = options.name || '';
        this.male = options.male || true;
        this.birthday = options.birthday;
    };
    
    User.schema = joi.object().keys({
        id: joi.number().integer().min(1),
        name: joi.string().required(),
        male: joi.boolean().default(true),
        birthday: joi.date().required()
    });
    
    User.find = function (id, callback) {
        client.hgetall("user:" + id, function (err, value) {
            if (err) {
                return callback(err);
            } else if (! value) {
                return callback(new Error("User not found"));
            }
    
            joi.validate(value, User.schema, callback);
        });
    };
    
    User.prototype.save = function (callback) {
        var value = {};
        for(var fieldName in this) {
            if (typeof(this[fieldName]) != 'function') {
                value[fieldName] = this[fieldName];
            }
        }
        joi.validate(value, User.schema, function (err, validatedValue) {
            if (err) {
                return callback(err);
            }
    
            client.hmset("user:" + validatedValue.id, validatedValue, callback);
        });
    };
    
    
    var user = new User({
        id: 1,
        name: "txf",
        male: true,
        birthday: new Date("1983-03-22")
    });
    
    user.save(function (err) {
        if (err) {
            console.error("user save error(" + err.toString() + ")");
            client.quit();
            return;
        }
    
        console.info("user saved");
    
        User.find(user.id, function (err, user) {
            client.quit();
            if (err) {
                console.error("user find error(" + err.toString() + ")");
                return;
            }
    
            console.log("user found: " + JSON.stringify(user));
        });
    });
    

    运行结果:

    user saved
    user found: {"id":1,"name":"txf","male":true,"birthday":"1983-03-22T00:00:00.000Z"}
    

node