巧用 Swagger 線上編輯器生成前端介面程式碼

vellengs發表於2018-07-01

Swagger 簡要介紹

Swagger / Open API 在Restful API 領域已慢慢成為標準,越來越多的系統使用swagger來規範開發介面文件,由於Swagger 本身並不依賴特定的語言和開發平臺,所以特別合適作為前後端分離的介面標準來使用。 Swagger 官方提供了兩種文件UI形式,一種是 Swagger UI, 另一種是 Swagger Editor.

  • Swagger UI 常常作為專案工程的一部份,很多程式都採用自身的特性,在程式程式碼上增加註釋、註解、裝飾器等方式完成swagger 的介面文件自動生成和文件展示。

  • Swagger Editor 提供了一個線上編輯的編輯器,使之能以文件的方式編輯介面,並提供了兩塊的生成功能:服務端程式碼與客戶端程式碼,程式碼生成涵蓋了大部分的主流語言與框架非常方便。

巧用 Swagger 線上編輯器生成前端介面程式碼

巧用 Swagger 線上編輯器生成前端介面程式碼

直接可用的程式碼

很多同學可能有疑問,這樣生成的程式碼到底能用嗎?

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

程式碼位置 github.com/vellengs/ty… 定製下provider 的 basePath 設定。

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

註冊下模組

ApiModule.forRoot(apiConfig),
複製程式碼

然後把目錄釋放到 github.com/vellengs/ty… 這個目錄,看清楚,generted目錄 是可以一字不改的,如果改了以後需要重新生成豈不是大麻煩?

放置到 angular 專案裡後就可以愉快的使用 service了,如下示例: github.com/vellengs/ty…

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 
複製程式碼

即可完成工作。

結束語,標準的介面在前後端分離的開發中起到很好的規範作用,而平滑的開發體驗也是重要的一環,如果你有疑問,或者有更好的方式,歡迎和作者交流學習 github.com/vellengs

相關文章