cnb-api-generate是一款基于swagger2.0标准协议生成基于@cnb/request和@reduxjs/toolkit的Typescript代码的工具。将Typescript中的Interface和Enum与swagger.json强绑定。并自动对请求函数的依赖分析并引入。
长期以来,前后端开发都是两套代码甚至多套代码各自维护。前端基于后端提供的接口定义,例如swagger.json中定义的接口入参出参,自行编写Typescript代码,用Typescript重新定义一遍接口的入参出参(Interface和Enum)。然后自行引用这些定义的入参出参(Interface和Enum)。
看似一切都很正常,实际上这里有一个致命问题,当后端接口主动或被动发生变更时,前端无感知。但是代码却能正常编译通过,当进入到运行时时,就会出现错误。问题核心就在于前端自行维护入参出参(Interface和Enum)和swargger.json中的定义是脱钩的。当后端代码发生变化,通过编译重新生成了swargger.json,但是新的swargger.json的变化并不能触达到前端。
swargger.json脱钩,swargger.json变化无法触发前端,编译通过,运行报错。Interface和Enum,可能存在认为失误写错代码。Interface和Enum。当使用cnb-api-generate后,Interface和Enum完全基于swargger.json中的定义自动生成标准的Typescript代码。并根据前端CNB的前端技术栈,完全自动生成多态化的网络函数调用,并自动完成对Interface和Enum的依赖注入。
swargger.json与所有的前端网络调用函数代码强绑定,当swargger.json变化后,重新生成前端代码,实现Typescript代码重新生成,从而在编译时就能发现类型错误的问题。Interface和Enum的定义完全自动化,完全基于swargger.json,无需人为干预。Typescript代码质量参差不齐。Typescript代码外,还会根据swargger.json定义每个参数的说明,自动生成jsDos的注释。npm install @cnbcool/cnb-api-generate -D
# or
yarn add @cnbcool/cnb-api-generate -D
在运行cag目录下创建cag.config.js文件。
module.exports = {
target: '<swargger.json文件地址>',
}
npx cag
# or
yarn cag
cnb-api-generate必须搭配@cnb/request使用!!!
cnb-api-generate基本不需要任何配置,为了灵活支持输入输出文件的位置和引用代码的自定义位置,提供一些简单的配置。
指定swagger.json的文件位置,路径为相对cag.config.js的路径。
指定输出的生成代码的目录,路径为相对cag.config.js的路径。
是否输出Redux Action代码,默认为true。
用于定义请求模块中依赖的函数与Typescript的定义
[key in string]: {
path: string;
isDefault: boolean;
}
基于@cnb/request,已内置,无需配置
cnb-api-generate基于swargger中定义的类型生成三类型代码,Interface、Enum和Api。其中Api会基于swargger中对接口的分类进行目录级归类输出。
对swagger中定义的definitions处理,生成Interface。
"dto.AiAutoPrResult": {
"type": "object",
"properties": {
"buildLogUrl": {
"description": "构建链接",
"type": "string"
},
"message": {
"description": "message",
"type": "string"
},
"sn": {
"description": "构建号",
"type": "string"
}
}
}
interfaces/dto.aiautoprresult.ts
export interface DtoAiAutoPrResult {
/**
* 构建链接
*/
buildLogUrl?: string;
/**
* message
*/
message?: string;
/**
* 构建号
*/
sn?: string;
}
在swagger的定义中,definitions是可以互相依赖的。cnb-api-generate会自动处理好所有依赖的文件引入,确保代码正常使用。
"api.CommitObject": {
"type": "object",
"properties": {
"author": {
"$ref": "#/definitions/api.Signature"
},
"comment_count": {
"type": "integer"
},
"committer": {
"$ref": "#/definitions/api.Signature"
},
"message": {
"type": "string"
},
"tree": {
"$ref": "#/definitions/api.CommitObjectTree"
},
"verification": {
"$ref": "#/definitions/api.CommitObjectVerification"
}
}
}
interfaces/api.commitobject.ts
import { ApiSignature } from "./api.signature";
import { ApiCommitObjectTree } from "./api.commitobjecttree";
import { ApiCommitObjectVerification } from "./api.commitobjectverification";
export interface ApiCommitObject {
author?: ApiSignature;
comment_count?: number;
committer?: ApiSignature;
message?: string;
tree?: ApiCommitObjectTree;
verification?: ApiCommitObjectVerification;
}
对swagger中定义的definitions处理,生成Interface。
"constant.ActivityType": {
"type": "string",
"enum": [
"mine",
"fork",
"follow",
"star",
"join_group",
"create_repo",
"user_create_release",
"repo_create_release",
"user_deploy_success",
"repo_deploy_success",
"at_user",
"comment"
],
"x-enum-comments": {
"AtUser": "AtUser @用户",
"Comment": "Comment pr,issue 评论",
"CreateRepo": "CreateRepo 创建仓库",
"Follow": "Follow 用户 follow",
"Fork": "Fork 仓库 fork",
"JoinGroup": "JoinGroup 加入组织",
"Mine": "Mine 与我相关的动态",
"RepoCreateRelease": "RepoCreateRelease 仓库发布版本",
"RepoDeploySuccess": "RepoDeploySuccess 仓库部署版本",
"Star": "Star 仓库 star",
"UserCreateRelease": "UserCreateRelease 用户发布版本",
"UserDeploySuccess": "UserDeploySuccess 用户部署版本"
},
"x-enum-descriptions": [
"Mine 与我相关的动态",
"Fork 仓库 fork",
"Follow 用户 follow",
"Star 仓库 star",
"JoinGroup 加入组织",
"CreateRepo 创建仓库",
"UserCreateRelease 用户发布版本",
"RepoCreateRelease 仓库发布版本",
"UserDeploySuccess 用户部署版本",
"RepoDeploySuccess 仓库部署版本",
"AtUser @用户",
"Comment pr,issue 评论"
],
"x-enum-varnames": [
"Mine",
"Fork",
"Follow",
"Star",
"JoinGroup",
"CreateRepo",
"UserCreateRelease",
"RepoCreateRelease",
"UserDeploySuccess",
"RepoDeploySuccess",
"AtUser",
"Comment"
]
}
enums/constant.activitytype.ts
export enum ConstantActivityType {
/* Mine 与我相关的动态 */
Mine = "mine",
/* Fork 仓库 fork */
Fork = "fork",
/* Follow 用户 follow */
Follow = "follow",
/* Star 仓库 star */
Star = "star",
/* JoinGroup 加入组织 */
JoinGroup = "join_group",
/* CreateRepo 创建仓库 */
CreateRepo = "create_repo",
/* UserCreateRelease 用户发布版本 */
UserCreateRelease = "user_create_release",
/* RepoCreateRelease 仓库发布版本 */
RepoCreateRelease = "repo_create_release",
/* UserDeploySuccess 用户部署版本 */
UserDeploySuccess = "user_deploy_success",
/* RepoDeploySuccess 仓库部署版本 */
RepoDeploySuccess = "repo_deploy_success",
/* AtUser @用户 */
AtUser = "at_user",
/* Comment pr,issue 评论 */
Comment = "comment",
}
cnb-api-generate是为cnb量身定做的代码生成工具,所以基于@cnb/request和@reduxjs/toolkit生成调用代码,并且自动完成对生成的interface和enum的引用依赖。
"/user/gpg-keys/{id}": {
"delete": {
"security": [
{
"BearerAuth": []
}
],
"consumes": [
"application/json"
],
"produces": [
"application/json",
"application/vnd.cnb.web+json"
],
"tags": [
"Users"
],
"summary": "删除用户 GPG key",
"operationId": "DeleteGPGKey",
"parameters": [
{
"type": "string",
"description": "gpg id",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK"
},
"404": {
"description": "Not Found",
"schema": {
"$ref": "#/definitions/die.WebError"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/die.WebError"
}
}
}
}
}
apis/users/delete-gpg-key.ts
import type { IncomingMessage } from "http";
import { createAsyncThunk } from "@reduxjs/toolkit";
import fetch from "@/request";
import { CnbRequestOptions, CnbRequestResult } from "@cnb/request";
import { AxiosRequestConfig } from "axios";
import { DieWebError } from "../../interfaces/die.weberror";
/**
* @description Other reuqest params
*/
type RequestConfig<DataType = any> = AxiosRequestConfig<DataType> & {
options?: CnbRequestOptions;
req?: IncomingMessage;
};
/**
* @description DeleteGPGKeyRes Success Response Type
*/
export type DeleteGPGKeyRes = unknown;
/**
* @description DeleteGPGKeyError Error Response Type
*/
export type DeleteGPGKeyError = DieWebError;
/**
* @description No description
* @tags Users
* @name deleteGPGKey
* @summary 删除用户 GPG key
* @request delete:/user/gpg-keys/{id}
----------------------------------
* @param {string} arg0
* @param {RequestConfig} arg1 - Other reuqest params
*/
export async function deleteGPGKey(
id: string,
{req, options, ...axiosConfig}: RequestConfig = {},
): Promise<CnbRequestResult<DeleteGPGKeyRes, DeleteGPGKeyError>> {
return await fetch.request<DeleteGPGKeyRes, DeleteGPGKeyError>({
...axiosConfig,
_next_req: req,
options: options,
url: `/user/gpg-keys/${id}`,
_apiTag: "/user/gpg-keys/{id}",
method: "delete",
});
}
基于swagger生成Agent Skill。
cag.config.js
module.exports = {
target: './template/swagger.json',
skillsOutputDir: `./`,
}
npx csg
生成如下目录结构:
| SKILL.md | scripts/ | - core/ | - modules/
skills运行需要依赖以下环境变量