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