巧用 Swagger 在线编辑器生成前端接口代码
发布于 3 个月前 作者 vellengs 844 次浏览 来自 分享

Swagger 简要介绍

Swagger / Open API 在Restful API 领域已慢慢成为标准,越来越多的系统使用swagger来规范开发接口文档,由于Swagger 本身并不依赖特定的语言和开发平台,所以特别合适作为前后端分离的接口标准来使用。 Swagger 官方提供了两种文档UI形式,一种是 Swagger UI, 另一种是 Swagger Editor.

  • Swagger UI 常常作为项目工程的一部份,很多程序都采用自身的特性,在程序代码上增加注释、注解、装饰器等方式完成swagger 的接口文档自动生成和文档展示。

  • Swagger Editor 提供了一个在线编辑的编辑器,使之能以文档的方式编辑接口,并提供了两块的生成功能:服务端代码与客户端代码,代码生成涵盖了大部分的主流语言与框架非常方便。

直接可用的代码

很多同学可能有疑问,这样生成的代码到底能用吗?

我的回答不仅是能用,而且很好用。 以 ng-alain 为例

代码位置 https://github.com/vellengs/typerx/blob/master/packages/client/src/app/delon.module.ts 定制下provider 的 basePath 设置。

export function apiConfig(): Configuration {
    return new Configuration({
        basePath: `${location.protocol}//${location.host}`
    });
}

注册下模块

ApiModule.forRoot(apiConfig),

然后把目录释放到 https://github.com/vellengs/typerx/tree/master/packages/client/src/generated 这个目录,看清楚,generted目录 是可以一字不改的,如果改了以后需要重新生成岂不是大麻烦?

放置到 angular 项目里后就可以愉快的使用 service了,如下示例: https://github.com/vellengs/typerx/blob/master/packages/client/src/app/pages/system/settings/settings.ts

profileSave(event?) {
    const entry: EditProfileDto = Object.assign({}, event);
    this.coreService.userUpdate(entry).subscribe((res) => {
        if (res) {
            this.settings.setUser(res);
            this.msg.success('个人资料修改成功');
        }
    });
}

saveSysSettings(event) {
    const entry = Object.assign({}, event);

    this.coreService.settingUpdateSettingsByName('main', entry).subscribe((res) => {
        if (res) {
            this.settingsData = res;
            this.msg.success('系统设置更新成功');
        }
    });
}

load() {
    this.coreService.settingGetSettingsByName('main').subscribe((res) => {
        if (res) {
            this.settingsData = res;
        }
    });
} 

方法变得可以感知了。

自动生成、下载、解压

上一步骤已经可以使用了,但是有点小小的麻烦;每次都要打开 editor.swagger.io 粘贴文档上去,然后去点生成,然后解压,这样是不是不够平滑呢?

那让我们写个脚本吧,自动完成上面的事情。 完整脚本地址

async function loadSwagger() {

    /** 读取 swagger.json 接口文档文件 */
    const jsonPath = path.resolve(process.cwd(), 'dist', 'swagger.json');
    const json = require(jsonPath);

    const client = axios.create({
        httpsAgent: new https.Agent({
            rejectUnauthorized: false
        })
    });

    /**
     * 提交 post 到服务器并获得下载链接
     */
    const result = await client.post(gateway, { spec: json });
    if (result.data && result.data.link) {
        const response = await client({
            method: 'GET',
            url: result.data.link,
            responseType: 'stream'
        })
        const local = path.resolve(process.cwd(), 'swagger.zip');
        const generatedFolder = path.resolve(process.cwd(), './../client/src/generated');
        const templateFolder = path.resolve(process.cwd(), 'decompress', 'typescript-angular-client');
        const decompress = path.resolve(process.cwd(), 'decompress');

        // 处理下载压缩包文件,解压并删除临时文件
        response.data.pipe(fs.createWriteStream(local)).on('finish', (done: any) => {
            fs.createReadStream(local).pipe(unzip.Extract({ path: 'decompress' })).on('close',
                async (done: any) => {
             
                    fs.unlinkSync(local); 
                    await removeFolder(generatedFolder);  
                    fs.renameSync(templateFolder, generatedFolder);
                    await removeFolder(decompress);
                });
        });
    }
}

/**
 * 若已经生成,则删除文件夹
 * @param folder 文件夹
 */
async function removeFolder(folder: string) {
    if (fs.existsSync(folder)) {
        await new Promise((resolve) => {
            rimraf(folder, () => {
                resolve(true);
            });
        })
    }
}

loadSwagger();

总共没几行代码,是不是觉得很简单呢,没错要的就是简单,但是很好的完成了我们的工作。

有了脚本之后你只要

ts-node  xxxxx/apigen.ts 

即可完成工作。

结束语,标准的接口在前后端分离的开发中起到很好的规范作用,而平滑的开发体验也是重要的一环,如果你有疑问,或者有更好的方式,欢迎和作者交流学习 https://github.com/vellengs 首发于掘金

回到顶部