fst-json 的全称是 "fast-safe-typescript json",它的实质就是间接应用你定义好的 Typescript 文件,来生成更加高效的序列化办法。
其目标是利用现有的资源(开发过程编写的 Typescript 文件),在编译和开发阶段尽可能进步运行时性能,同时这个过程并没有额定的开发累赘。

github: https://github.com/aircloud/f...

背景

因为 JSON schema 这个概念是由 fastify 引入,咱们先对此进行介绍。

fastify 是一个高性能 Node.JS 服务端框架,其特点就是高性能,而之所以高性能次要的起因就是它引入了 JSON schema,通过对参数减少束缚,来取得更快的序列化速度。

同时,fastify 也开源了一个独立的 json 序列化库 fast-json-stringify,能够在非 fastify 的我的项目中应用

在 fastify 中,JSON schema 的大抵写法如下:

const schema = {  schema: {    response: {      200: {        type: 'object',        properties: {          hello: {            type: 'string'          }        }      }    }  }}fastify  .get('/', schema, function (req, reply) {    reply      .send({ hello: 'world' })  })

咱们能够看出,这一套写法不仅会带来额定的学习老本,而且因为目前大多数我的项目开发都是采纳 Typescript,这套定义也会和咱们的 Typescript 定义有所反复。

事实上,尽管下面的示例代码比拟短小,然而在理论的我的项目中,接口比拟多的状况下,这些代码的开发量和额定的学习/保护老本还是不容小视的。

那么有没有可能间接应用 Typescript,而不必从新定义 JSON schema 呢?

答案是有的。

fst-json 就是这样一个工具,它能够通过复用咱们在 Typescript 中定义的 schema,通过工具主动生成 fastify 须要的 schema,这样咱们就无需额定保护 schema 定义了。

应用形式

接下来,咱们简略介绍 fst-json 的应用形式,首先装置(全局或者装置到我的项目中):

npm i fst-json -g

假如咱们我的项目采纳了 Typescript,当时曾经有了 schema 文件:

export interface HellWorld {  attr1: string;  attr2: string;  attr3?: string;}

咱们在我的项目目录下新建 .fstconfig.js,用于申明配置,配置如下:

module.exports = {  sourceFiles: [    './src/schema/*.ts'  ],  distFile: "./src/schema-dist.ts",  format: 'fastify'}

之后咱们运行:

fst-json gen

而后此时会生成一个 src/schema-dist.ts,这里会有主动生成的 JSON schema 定义,接下来咱们在我的项目中能够同时应用 JSON schema 定义和咱们之前定义好的 Typescript 类型:

import * as schemas from './schema-dist';import type { HellWorld  } from "./schema";const schema = {  schema: {    response: {      200: schemas.HellWorldSchema    }  }}server  .get('/', schema, function (req, reply) {    let res: HellWorld = {      attr1: 'hello',       attr2: 'world',       attr3: 'optional'    }    reply      .send(res);  })

当然,fst-json 不仅仅能够在 fastify 中应用,也能够在任何其余须要 JSON 减速的中央应用,用法也都很简略,能够参考这个 HelloWorld

原理和劣势

fst-json,实际上是通过对 Typescript 进行语法树解析,针对 export 导出的各种类型生成对应的 fast-json-stringify 的 JSON schema,所以运行速度和手写是没有区别的。因而,它不仅仅能齐全应用 fast-json-stringify 的效率劣势,除了缩小反复开发量以外还有如下长处:

  • 依据 schema 进行字段校验: 首先会进行 Tyepscript 语法校验,另外当缺失必须的属性(例如,当定义 interface 时没有被 ? 修饰符润饰的属性缺失)的时候也会间接报错。
  • 过滤不须要的 schema 字段: 例如当把 Node.JS 当作 BFF 层的时候,能够严格依照 Typescript 的定义来返回字段,防止返回不须要的字段,从而防止上游服务的敏感字段被间接透传出去,也意味着从接口层面开始,真正做到 Fully Typed。
  • 更快的序列化速度: 依据 fast-json-stringify 的测试,能达到靠近 2 倍的 JSON 序列化速度。

目前,fst-json 对罕用的各类 interface、class、type 等类型定义都进行了反对,并且减少了各类 examples 和 90% 的覆盖率测试。

当然,因为 Typescript 的写法比拟灵便。出于 JSON schema 自身的局限性,咱们无奈笼罩所有场景,所以也能够参考这里的注意事项,有针对性的对比拟容易出问题的写法进行躲避。

局限性

fst-json 只是语法解析和生成工具,具体的运行时,实际上就是在应用 fast-json-stringify,也因而我的项目中须要装置 fast-json-stringify 依赖。

另外,针对 fast-json-stringify 的测试,在比拟小的 payload 的状况下,它的速度是有劣势的,当 payload 过大的时候,它的劣势不再显著,甚至还不如 JSON.stringify。官网的形容是:

fast-json-stringify is significantly faster than JSON.stringify() for small payloads.
Its performance advantage shrinks as your payload grows.

不过事实上,这个时候你依然能够应用 fst-json 做一些事件,例如笔者应用 fst-json 来做 bff 层对上游服务接口的继续集成兼容测试,在 Typescript 曾经提前定义好了的状况下,每次测试的时候只须要申请依赖服务并且把响应字段序列化,如果没有报错并且字段序列化之后也没有变成 null(在比较复杂的接口定义中,如果个别属性定义类型和返回类型不统一,fast-json-stringify 是会间接转换成 null),就阐明接口是没有变动的。能够无效防止依赖服务接口变动,却又没有及时同步到位造成暗坑的状况。

另外,其实目前 fast-json-stringify 生成序列化代码还是在运行时做的,这里的问题可能在于代码不通明,以及运行时开销和危险,笔者是心愿将它的生成代码变成编译时去做,不过这样的话实际上有一点反复造轮子的错觉,所以目前还没有做这个事件。


最初 fst-json 作为一个开源不久的小我的项目,必定还有些须要优化和欠缺的中央,欢送 star 反对和提出倡议。