likes
comments
collection
share

lowcode, 简单的json校验方案分享

作者站长头像
站长
· 阅读数 55

前言:为什么要做

由于近几年低代码的火热,为了提高一些开发效率和降低开发成本,现在很多页面喜欢用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'
      }
    ])
  })
})

lowcode, 简单的json校验方案分享

需要注意:

生成json-schema、与json-schema的校验。这两块的性能都不是很好。生成json-schema这块我们可以不必关注,我们一般可以在编译阶段去做。但是校验这块,尽量只做前置校验或后置兜底的操作。如果不care性能问题,那就无所畏惧了🫤

转载自:https://juejin.cn/post/7250670781633511484
评论
请登录