字节都在用的代码自动生成

背景

如果有一份接口定义,前端和后端都能基于此生成相应端的代码,不仅能降低前后端沟通成本,而且还能提升研发效率。

字节内部的 RPC 定义主要基于 thrift 实现,thrift 定义了数据结构和函数,那么是否可以用来作为接口定义提供给前端使用呢?如果可以作为接口定义,是不是也可以通过接口定义自动生成请求接口的代码呢?答案是肯定的,字节内部已经衍生出了多个基于 thrift 的代码生成工具,本篇文章主要介绍如何通过 thrift 生成前端接口调用的代码。

接口定义

接口定义,顾名思义就是用来定义接口的语言,由于字节内部广泛使用的 thrift 基本上满足接口定义的要求,所以我们不妨直接把 thrift 当成接口定义。

thrift 是一种跨语言的远程过程调用 (RPC) 框架,如果你对 Typescript 比较熟悉的话,那它的结构看起来应该很简单,看个例子:

namespace go namesapce

// 请求的结构体
struct GetRandomRequest {
    1: optional i32 min,
    2: optional i32 max,
    3: optional string extra
}

// 响应的结构体
struct GetRandomResponse {
    1: optional i64 random_num
}

// 定义服务
service RandomService {
   GetRandomResponse GetRandom (1: GetRandomRequest req)
}
复制代码

示例中的 service 可以看成是一组函数,每个函数可以看成是一个接口。我们都知道,对于 restful 接口,还需要定义接口路径(比如 /getUserInfo)和参数(query 参数、body 参数等),我们可以通过 thrift 注解来表示这些附加信息。

namespace go namesapce

struct GetRandomRequest {
    1: optional i32 min (api.source = "query"),
    2: optional i32 max (api.source = "query"),
    3: optional string extra (api.source = "body"),
}

struct GetRandomResponse {
    1: optional i64 random_num,
}

// Service
service RandomService {
   GetRandomResponse GetRandom (1: GetRandomRequest req) (api.get = "/api/get-random"),
}
复制代码

api.source 用来指定参数的位置,query 表示是 query 参数,body 表示 body 参数;api.get="/api/get-random" 表示接口路径是 /api/get-random,请求方法是 GET;

生成 Typescript

上面我们已经有了接口定义,那么对应的 Typescript 应该就呼之欲出了,一起来看代码:

interface GetRandomRequest {
    min: number;
    max: number;
    extra: string;
}

interface GetRandomResponse {
    random_num: number;
}

async function GetRandom(req: GetRandomRequest): Promise<GetRandomResponse> {
    return request<GetRandomResponse>({
        url: '/api/get-random',
        method: 'GET',
        query: {
            min: req.min,
            max: req.max,
        },
        body: {
            extra: req.extra,
        }
    });
}

复制代码

生成 Typescript 后,我们无需关心生成的代码长什么样,直接调用 GetRandom 即可。

架构设计

要实现基于 thrift 生成代码,最核心的架构如下:

 

因为 thrift 的内容我们不能直接拿来用,需要转化成中间代码(IR),这里的中间代码通常是 json、AST 或者自定义的 DSL。如果中间代码是 json,可能的结构如下:

{
    name: 'GetRandom',
    method: 'get',
    path: '/api/get-random',
    req_schema: {
        query_params: [
            {
                name: 'min',
                type: 'int',
                optional: true,
            },
            {
                name: 'max',
                type: 'int',
                optional: true,
            }
        ],
        body_params: [
            {
                name: 'extra',
                type: 'string',
                optional: true,
            }
        ],
        header_params: [],
    },
    resp_schema: {
        header_params: [],
        body_params: [],
    } 
}
复制代码

为了保持架构的开放性,我们在核心链路上插入了 PrePlugin 和 PostPlugin,其中 PrePlugin 决定了 thrift 如何转化成 IR,PostPlugin 决定 IR 如何生成目标代码。

这里之所以是「目标代码」而不是「Typescript 代码」,是因为我希望不同的 PostPlugin 可以产生不同的目标代码,比如可以通过 TSPostPlugin 生成 Typescript 代码,通过 GoPostPlugin 生成 go 语言的代码。

总结

代码生成这块的内容还有很多可以探索的地方,比如如何解析 thrift?是找第三方功能生成 AST 还是通过 pegjs 解析成自定义的 DSL?多文件联编如何处理、字段名 case 如何转换、运行时类型校验、生成的代码如何与 useRequest 或 ReactQuery 集成等。

thrift 其实可以看成接口定义的具体实现,如果 thrift 不满足你的业务场景,也可以自己实现一套类似的接口定义语言;接口定义作为前后端的约定,可以降低前后端的沟通成本;代码生成,可以提升前端代码的质量和研发效率。

如果本文对你有启发,欢迎点赞、关注、留言交流。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
自动生成GUID软件是一种能够帮助用户生成全局唯一标识符(GUID)的软件工具。GUID是一种由16个字节组成的字符串,以保证在全球范围内的唯一性。使用GUID可以确保在分布式系统中的各个组件或实体之间进行唯一标识和定位。 自动生成GUID软件通常具备以下功能: 1. 高效生成:软件能够迅速生成GUID,让用户在需要时能够方便地获得唯一标识符。 2. 多种生成方式:软件可以提供多种生成GUID的方式,如随机生成、基于时间戳生成等。这样用户可以根据具体需求选择适合的生成方式。 3. 批量生成:软件支持批量生成GUID,用户可以一次性生成多个GUID,提高工作效率。 4. 可定制性:软件允许用户进行一定程度的定制,例如可以设置GUID的长度、格式等,以符合不同系统或应用的要求。 5. 图形界面:软件提供直观的图形界面,使得用户能够轻松操作和管理生成的GUID。 6. 导出与导入:软件可以支持生成的GUID的导出与导入,方便用户进行备份和恢复。 7. 集成接口:软件可以提供与开发工具和应用程序集成的接口,方便开发人员在代码中使用生成的GUID。 通过使用自动生成GUID软件,用户可以摆脱手动生成GUID的复杂和不便,简化工作流程,提高工作效率。这种软件在分布式系统、数据库管理、身份识别验证等领域具有重要的作用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

丶张豪哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值