跳至主要內容
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?

4563博客

全新的繁體中文 WordPress 網站
  • 首頁
  • 为 HTTP 请求的 JSON 响应自动生成 TS 类型
未分類
30 8 月 2021

为 HTTP 请求的 JSON 响应自动生成 TS 类型

为 HTTP 请求的 JSON 响应自动生成 TS 类型

資深大佬 : ThomasTrainset 15

使用 TypeScript 开发前端项目,完善的类型批注是非常提升开发效率的。然而,当遇到 Restful,似乎只能为 Restful 返回的 JSON 数据手动书写类型,随着接口越来越多,手写类型是繁琐且低效的。 有没有一种简单的方式,可以拿到返回数据的类型呢?

JSON 类型文件生成

JSON 类型

Json 中数据类型有 6 种: string 、number 、boolean 、array 、object 、null

其中 string 、number 、boolean 的类型可以直接使用 typeof 判别类型。

null 有些复杂,它可能是其他 5 中类型中的一种,无法判断具体是什么类型,因而只能填充 any

对于 object,它可能由 Json 的 6 种数据结构组成,可以使用递归遍历的方式,来判断 value 的类型

而对于 array,array 中的每一项数据结构应当都是相同的,因而只需要取出第一项进行处理,处理逻辑与上述几种类型相同。

文件生成

可以使用 node fs api,利用拼接字符串的形式,将 JSON 类型处理后,输出到类型文件中。这样简单且有效,但不那么优雅,且易出错。

可以借助 ts-morph 这个库,来完成类型的生成和导出。

ts-morph 使用伪代码如下:

 const project = createProject()  project.addInterface({ name, value }).setIsExport(true)  saveProject(project)  

相比 fs API,ts-morph 使用更简单

Restful 整合

可以根据 JSON 数据生成类型文件后,很容易想到,在请求库的拦截器中,拦截响应,执行 JSON 类型文件生成。但值得注意的是,前端项目中,Node API 不能使用,因为你的代码是运行在浏览器的。那么怎么解决这个问题呢?

类型生成器脚本

既然前端项目中不能集成 JSON 类型文件生成工具,那么可以编写 Node 脚本来解决问题。后端提供一个接口后,前端新增一个接口,脚本配置文件也要注册一个接口,最后运行一下脚本即可。

那么看看脚本需要完成哪些功能。

首先脚本需要集成一个请求库,用以发起请求,接收服务端的 JSON 数据。

然后还要集成上面的 JSON 类型文件生成脚本。

此外,还需要维护一份配置文件,文件中要有请求参数列表,用以动态生成类型文件。为了避免同时发起的请求数量太多,导致电脑死机,或者服务端宕机,还要对请求进行并发控制。

每次执行脚本,所有请求都会再发送一遍,所以还要考虑检测文件是否生成,再去请求。

考虑到可维护性,建议单独维护一个 URL 的映射文件,在 Node 脚本和前端项目,引用 URL 文件的 URL 地址。

有了这样一个脚本,每次新增一个接口时,需要在配置文件中配一下接口和请求参数,然后手动执行一下脚本。这样也不太方便,可以使用 chokidar 监听文件变更,使用 shelljs 来执行脚本。

可以看到,上面的步骤繁琐且复杂,维护这样一个复杂配置文件,会让人望而却步。并且这样的配置文件对于一些复杂的请求,涉及到的 Token 校验,Post 的 Body 处理,响应的 Data 的处理等等都要区别与前端项目,再单独处理一遍。

有没有更好的办法,来完成类型生成的目的?

Server-Clinet 类型生成器

写这样一个脚本,主要的难点在于 Node 脚本怎么便捷的拿到前端项目的响应数据,也就是前端拿到数据后怎么通知到脚本?

这么一想,事情就简单了,如果 Node 脚本中开启一个 HTTP Server,前端拿到数据后,再向 HTTP Server 发起一个 POST 请求,将一些参数携带过去,指挥 HTTP Server 向目标目录生成类型文件即可。

但这一套流程还有个缺点,类型文件是“运行时”生成的,生成类型文件前,需要前端项目先调用一次请求。但是,这一点缺点无伤大雅,开发代码时,肯定需要先测试接口能不能通什么的。

工具链

基于几天的尝试,我开发了几个库,完成了这样一件事情,最后看 demo 的效果,还不错。

Demo 项目

我基于 Vite React TypeScript 写了一个 demo 项目:restful-types-generate-example。

clone 项目后,运行 yarn 安装, yarn dev 启动项目,点击页面按钮,发起请求后即可看到效果。

为 HTTP 请求的 JSON 响应自动生成 TS 类型

JsonTypesGenerator

json-types-generator 是根据第一小节中介绍的原理完成的

使用方式如下:

 import jsonTypesGenerator from 'json-types-generator'  const json = { a: { b: 1, c: { d: true } } }  jsonTypesGenerator({    data: json,    outPutPath: '/User/xdoer/types.ts',    rootInterfaceName: 'ChinaRegion',    customInterfaceName(key, value, data) {      if (key === 'a') return 'Province'      return key    }, }) 

上面的代码,将会在 /User/xdoer/types.ts 文件中生成导出 interface 为 ChinaRegion 的类型文件,产生的中间 inteface 名称为 Province。不传入 customInterfaceName 的情况下,中间产物默认的 interface 名称为 key 的大写

<!----/User/xdoer/types.ts---->  export interface ChinaRegion {   a: Province }  export interface Province {   b: number   c: c }  export interface c {   d: boolean } 

ResponseTypesServer

response-types-server 是上文提到的 Server-Clinet 类型生成器 中的 Server 部分。只需要向这个 Server 发送 POST 请求,即可生成类型。

使用方式如下:

import server from '@prequest/response-types-server'  // 默认开启的端口为 10086 server()  // 你可以通过传参指定端口 server({ port: 10010 }) 

发送的请求,路径任意,POST 请求参数为:

参数 类型 含义
outPutDir string 类型文件输出目录
outPutName string 文件名称
overwrite boolean 文件可复写
data Json 要解析的 Json 数据
interfaceName string 导出的接口名称

ResponseTypesClient

response-types-client 是上文提到的 Server-Clinet 类型生成器 中的 Client 部分。它是一个中间件 Wrapper,只要将其注册到请求库中间件中,即可发起请求。

下面的 demo 使用了我自己封装的请求库 PreQuest,基于 Koa 中间件模型的请求库应该都可以使用,比如说 Umi-Request 。对于 Axios,需要自己在拦截器中实现,也非常容易。

使用方式如下:

 import { create, Request, Response } from '@prequest/xhr' import generateMiddleware, { TypesGeneratorInject } from '@prequest/response-types-client'  // 生成中间件 const middleware = generateMiddleware<Request, Response>({    enable: process.env.NODE_ENV === 'development',    httpAgent: create({ path: 'http://localhost:10010/' }),    outPutDir: 'src/api-types'    parseResponse(res) {       // res 应当返回接口 data 数据       return res as any    },     typesGeneratorConfig(req, res) {      const { path } = req      const { data } = res            if (!path) throw new Error('path not found')       // 根据请求路径生成文件名和类型导出名称      const outPutName = path.replace(/.*/(w+)/, (_, __) => __)      const interfaceName = outPutName.replace(/^[a-z]/, g => g.toUpperCase())       return {        data,        outPutName,        interfaceName,        overwrite: true      } }})  // 注入 TypesGeneratorInject, 可在请求时,根据 rewriteType 参数强制重新生成类型文件 export const prequest = create<TypesGeneratorInject, {}>({ baseURL: 'http://localhost:3000' })  // 注册中间件 prequest.use(middleware) 

ResponseTypesGenerator

此外,还有基于上文 “类型生成器脚本” 一节中的原理,进行了一个失败的尝试:response-types-generator,也一并放到这里,感兴趣的可以看看

结语

以上基于我浅薄的学识进行的一些对 Restful 响应的 JSON 数据类型生成的一些探索,如果您发现了文中的一些错误之处,或者有更简便的方式生成类型文件,欢迎在评论里提出来,大家一起探讨。

原文首发于我的个人博客:Restful-API 的一种动态生成数据类型的方法 | 文享日志 (aiyou.life)

大佬有話說 (0)

文章導覽

上一篇文章
下一篇文章

AD

其他操作

  • 登入
  • 訂閱網站內容的資訊提供
  • 訂閱留言的資訊提供
  • WordPress.org 台灣繁體中文

51la

4563博客

全新的繁體中文 WordPress 網站
返回頂端
本站採用 WordPress 建置 | 佈景主題採用 GretaThemes 所設計的 Memory
4563博客
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?
在這裡新增小工具