Swagger 簡要介紹
Swagger / Open API 在Restful API 領域已慢慢成為標準,越來越多的系統使用swagger來規範開發介面文件,由於Swagger 本身並不依賴特定的語言和開發平臺,所以特別合適作為前後端分離的介面標準來使用。 Swagger 官方提供了兩種文件UI形式,一種是 Swagger UI, 另一種是 Swagger Editor.
-
Swagger UI 常常作為專案工程的一部份,很多程式都採用自身的特性,在程式程式碼上增加註釋、註解、裝飾器等方式完成swagger 的介面文件自動生成和文件展示。
-
Swagger Editor 提供了一個線上編輯的編輯器,使之能以文件的方式編輯介面,並提供了兩塊的生成功能:服務端程式碼與客戶端程式碼,程式碼生成涵蓋了大部分的主流語言與框架非常方便。
直接可用的程式碼
很多同學可能有疑問,這樣生成的程式碼到底能用嗎?
我的回答不僅是能用,而且很好用。 以 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