blog icon indicating copy to clipboard operation
blog copied to clipboard

编写一个简单,优雅,可扩展的JS数据校验库Struct

Open axetroy opened this issue 6 years ago • 3 comments

Why?

在开发中,经常遇到数据校验,需要一个简单的,精准的优雅校验数据库对一些数据进行校验。

场景如下:

  • 配置文件校验
  • 与他人对接的数据校验
  • 接口参数的校验
  • and so on...

社区找了一遍,好像并没有我想要的,索性就自己写一个,撸起袖子就是干。

本文主要讲解如何使用,以及实现原理。

API预览

const Struct = require("@axetroy/struct");

const data = {
  name: "axetroy",
  age: 18
};

const struct = new Struct({
  name: Struct.type.string,
  age: Struct.type.int
});

const err = struct.validate(data);

console.log(err); // undefined, because the data pass the validator

实现原理

  1. 构造Struct对象,传入各字段的类型
  2. 类型定义使用Struct.type.xxx
  3. 调用struct.validate(data)进行校验

解析:

Struct.type返回的是 new Type(), 而Type对象的原型上,定义了一系列内置方法。

访问Struct.type.string其实就是访问了new Type().string, 会产生一个校验器,加入到type的队列里面,返回返回this,方便链式调用

在运行struct.validate(data)的时候,获取字段对应的Type, 然后逐一执行队列里面的函数,全部通过才算通过,返回undefined, 否则返回错误。

支持的类型

内置支持了int, float, string,等等。以及支持对象嵌套的校验,支持数组校验。

内置的不够? 那就来自定义吧

调用Struct.define(name, func), 在Type.prototype上添加相应的方法。

例如Struct.define("email", func),那么可以这么添加校验器Struct.type.email

一个字段可以有多个校验器(链式调用)

完整例子如下:

const Struct = require("../index");

Struct.define("email", function(input) {
  return /^[a-z0-9]+([._\\-]*[a-z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$/.test(
    input
  );
});

const data = {
  name: "axetroy",
  age: 18,
  email: "[email protected]"
};

const struct = truct({
  name: Struct.type.string,
  age: Struct.type.int,
  email: Struct.type.string.email // check string first, and then check email
});

const err = struct.validate(data);

console.log(err); // undefined, because the data pass the validator

你甚至可以定义一个带参数的类型校验, 这里有demo

最后

代码已经过测试,覆盖率接近100%,可放心食用

顺便弱弱的问一句,object.hasOwnProperty(key)分支的测试,为什么老是没有覆盖

欢迎大牛们来搞,issue or PR

https://github.com/axetroy/struct

原文地址: http://axetroy.xyz/#/post/136

axetroy avatar Nov 24 '17 14:11 axetroy

大神参考你的作品我也写了一个,浏览器可以直接运行的版本。追加了enum类型,default参数和formatData功能。有机会交流交流啊 https://github.com/LOVEtheWayuLie/js-Struct

LOVEtheWayuLie avatar Feb 22 '18 12:02 LOVEtheWayuLie

@LOVEtheWayuLie 哈,你写得很不错,不过我给点建议啊

  1. 加上测试用例
  2. 使用打包工具打包umd模块,而不是直接挂载在windows下

axetroy avatar Feb 22 '18 16:02 axetroy

@axetroy 恩恩,谢谢。 一直没有在浏览器外的地方写过js,所以就写在了window下,我会努力去学习写一些在哪都能跑的js的。

  • 那个我测试了一下你的json验证, 不是很完善。 typeof JSON.parse('null') === ‘object’ 也会通过的

LOVEtheWayuLie avatar Feb 23 '18 01:02 LOVEtheWayuLie