lowcode, 简单的json校验方案分享
前言:为什么要做
由于近几年低代码的火热,为了提高一些开发效率和降低开发成本,现在很多页面喜欢用json去描述。
但是呢,在这过程中也带来了一些问题。
由于某些异常情况,可能会导致我们的json数据发生错乱。比较常见的现象就是页面崩溃,需要由研发同学去排查问题。
由于json的数量通常较大且某些研发同学对代码的熟悉度有限,这给排错工作带来了巨大的挑战。可能需要人工检查几兆级别的json数据中的错乱数据。
在表现方面,页面崩溃并不是最严重的情况。例如,去年我负责一个与金钱挂钩的活动相关的低代码平台。如果由于json异常错乱导致错误的活动配置上线,那将带来更可怕的影响。
怎么做
首先回想一下,社区中本身是存在一个已经提供了相关校验功能的JSON Schema
。但是有相当一部分人是不喜欢它的,因为它的特定格式和学习成本。我们有时候不希望自身设计的DSL
还要受到限制。
但是既然它本身提供了校验的功能,我们能不能去写一个中间层去做一下JSON到JSON Schema的转换呢?JSON到JSON Schema的转换不太可能,因为拿不到类型定义,校验所需信息无从获取。但是我们还用TS呢,是不是可以先用TS先对JSON进行类型定义,然后可以做TS到JSON Schema的转换呢?
围绕着这个思路,社区中已有相关的实现方案。我这选其中一个给大家演示一下
栗子🌰:
比如我们设计了这么一段结构
interface Person {
name: string
age: number
address?: {
street: string
city: string
country: string
}
}
期望在运行时可以生成一个方法,对下面的json数据进行格式校验。
{
name: 11,
age: 11
}
步骤1: 根据ts生成json-schema
ts生成json-schema,可以借助typescript-json-schema
常见类型存放目录type.ts
interface Person {
name: string
age: number
address?: {
street: string
city: string
country: string
}
}
解析ts生成json-schema
import * as path from 'path'
import { buildGenerator, getProgramFromFiles } from 'typescript-json-schema'
function ts2jsonchema() {
const program = getProgramFromFiles([
path.resolve(__dirname, '../types/index.ts'),
])
const generator = buildGenerator(program, { required: true })
return generator!.getSchemaForSymbol('Person')
}
步骤2: 借助json-schema生成校验方法
校验库可以选择ajv
ajv的使用也非常简单,传入指定的jsonchema。就可以快速生成一个对应的校验方法
import Ajv from 'ajv'
function validate() {
const ajv = new Ajv()
const validate = ajv.compile(ts2jsonchema())
return validate
}
步骤3: 验证
仅需简单几个步骤,我们已经快速构建一了一个对Person
类json的校验方法,简单写一个单元测试验证一下吧。
{
name: 11,
age: 11
}
这段数据肯定是不满足的,因为我们定义的name是string。并且我们希望能给出一个错误的定位,像json-schema标准格式这样
{
instancePath: '/name',
schemaPath: '#/properties/name/type',
keyword: 'type',
params: { type: 'string' },
message: 'must be string'
}
jest代码如下:
import validate from '../validate'
describe('validate', () => {
it('base', () => {
const validateFn = validate()
const valid = validateFn({
name: 11,
age: 11
})
// name must be string
expect(valid).toBe(false)
expect(validateFn.errors).toEqual([
{
instancePath: '/name',
schemaPath: '#/properties/name/type',
keyword: 'type',
params: { type: 'string' },
message: 'must be string'
}
])
})
})
需要注意:
生成json-schema、与json-schema的校验。这两块的性能都不是很好。生成json-schema这块我们可以不必关注,我们一般可以在编译阶段去做。但是校验这块,尽量只做前置校验或后置兜底的操作。如果不care性能问题,那就无所畏惧了🫤
转载自:https://juejin.cn/post/7250670781633511484