使用 Swagger 自動生成 API 文件

前言

通常我們在開發後端時,時常開發完畢之後必須撰寫 API 文件,因此這一邊就來介紹一下,如何自動生成 API 文件。

開發環境

  • Node.js 14
  • Express
  • MacOS Big Sur

雖然這邊列上了開發環境,但實際上後面還是會提供範例程式碼。

自動產生 API 文件

這邊我們將會使用 Swagger,而 Swagger 是什麼呢?這邊擷取 wiki 部分說明

Swagger 與一組開源軟件工具一起使用,以設計,構建,記錄和使用RESTful Web服務。Swagger包括自動文檔,代碼生成和測試用例生成。

簡單來講就是方便後端 API 介接時有一個更直覺的 GUI 介面,透過 Swagger UI 你可以生成一個網頁,讓你可以直接在網頁上測試 API 以及了解狀況。

Swagger UI

講那麼多廢話,那麼該如何實際應用在自己專案中呢?這邊我將會使用 Express 作為範本。

1
express --pug --css sass // 建立之後記得進入該目錄輸入 npm install

(在此我是使用「Express 應用程式產生器」建立,若沒有安裝的話則可以試著安裝 npm install express-generator -g。)

Express

接下來我們要替專案安裝兩個重點套件

1
npm install --save swagger-autogen swagger-ui-express

swagger-autogen

swagger-ui-express 簡單來講就是讓 Express 支援 swagger 的 UI 介面呈現而已,這邊的自動化產生 API 的重點套件在於 swagger-autogen。

swagger-autogen 是什麼呢?簡單來講,你只需要在 API 的 router 撰寫註解,那麼在執行 swagger-autogen 時,它就會自動依照註解內容生成 API 文件,是不是超貼心呢?

因此接下來我們要建立一個檔案叫做「swagger.js」,內容則是以下

1
2
3
4
5
6
const swaggerAutogen = require('swagger-autogen')();

const outputFile = './swagger_output.json'; // 輸出的文件名稱
const endpointsFiles = ['./app.js']; // 要指向的 API,通常使用 Express 直接指向到 app.js 就可以

swaggerAutogen(outputFile, endpointsFiles); // swaggerAutogen 的方法

接下來讓我們修改一下 router,通常預設會生成兩個 router

  • 「router/index.js」
  • 「router/users.js」

然後內容多增加一些 router,這邊會有兩種寫法

第一種寫法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
router.get('/', function(req, res, next) {
res.send('respond with a resource');
});

router.post('/post', function(req, res, next) {
res.send('respond with a resource');
});

router.put('/put', function(req, res, next) {
res.send('respond with a resource');
});

router.delete('/delete', function(req, res, next) {
res.send('respond with a resource');
});

第二種寫法

1
2
3
4
5
6
7
8
9
10
11
12
router.get('/', function (req, res, next) {
res.render('index', { title: 'Express' });
})
.post('/post', function (req, res, next) {
res.render('index', { title: 'Express' });
})
.put('/put', function (req, res, next) {
res.render('index', { title: 'Express' });
})
.delete('/delete', function (req, res, next) {
res.render('index', { title: 'Express' });
});

接下來修改 package.json 增加一行指令

1
2
3
"scripts": {
"swagger-autogen": "node ./swagger.js"
},

因此我們就可以輸入 npm run swagger-autogen,這邊當你輸入之後就會出現以下訊息

swagger

當看到 swagger-autogen 顯示 「Swagger-autogen: Success ✔」,就會發現專案生成了一個 JSON 檔案叫做「swagger_output.json」,這邊可以不用太過理會。

swagger-ui-express

最後我們來修改一下 app.js,畢竟我們都安裝了 swagger-ui-express,也就代表我們希望在 Express 上運行 Swagger UI,這邊只需要加入以下程式碼即可

1
2
3
4
const swaggerUi = require('swagger-ui-express')
const swaggerFile = require('./swagger_output.json') // 剛剛輸出的 JSON

app.use('/api-doc', swaggerUi.serve, swaggerUi.setup(swaggerFile))

接下來輸入 npm start 並進入特定「http://localhost:3000/api-doc/」就可以看到自動生成的 API 文件囉

Swagger UI

swagger-autogen 註解撰寫

在上面圖中可以看到我的 API 有依照 API 去區分區塊,而這部分是如何做到的呢?其實在 swagger-autogen 是有提供範例程式碼的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
const swaggerAutogen = require('swagger-autogen')()

const doc = {
info: {
"version": "", // by default: "1.0.0"
"title": "", // by default: "REST API"
"description": "" // by default: ""
},
host: "", // by default: "localhost:3000"
basePath: "", // by default: "/"
schemes: [], // by default: ['http']
consumes: [], // by default: ['application/json']
produces: [], // by default: ['application/json']
tags: [ // by default: empty Array
{
"name": "", // Tag name
"description": "" // Tag description
},
// { ... }
],
securityDefinitions: { }, // by default: empty object
definitions: { } // by default: empty object
}

const outputFile = './path/swagger-output.json'
const endpointsFiles = ['./path/endpointsUser.js', './path/endpointsBook.js']

swaggerAutogen(outputFile, endpointsFiles, doc)

因此在我們的 swagger.js 就可以這樣調整

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const swaggerAutogen = require('swagger-autogen')();

const doc = {
tags: [ // by default: empty Array
{
name: "Index",
description: "首頁 router"
},
{
name: "Users",
description: "使用者 router"
},
],
}

const outputFile = './swagger-output.json';
const endpointsFiles = ['./app.js'];

swaggerAutogen(outputFile, endpointsFiles, doc);

接下來回到每一個 router 的相關 JS,依照官方範例可以這樣寫,基本上寫法有兩種形式,一個是使用單行註解與多行註解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
...
app.get('/users/:id', (req, res) => {
...
// #swagger.tags = ['Index']
...
})

app.post('/users', (req, res) => {
...
/*
#swagger.tags = ['Users']
} */
users.addUser(req.body)
...
})

只需要在每一個 router 裡面撰寫註解,這樣 swagger-autogen 就會依照註解自己去生成並分類,甚至是生成註解說明等等。

這邊就不再次展示,而官方的文件本身就寫得滿清楚該如何撰寫註解,因此這邊就不一一介紹了。

比較特別的是 swagger-autogen 也可以針對單一 function 去做撰寫

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
function myFunction(param) {
// #swagger.start
...
/*
#swagger.path = '/forcedEndpoint/{id}'
#swagger.method = 'put'
#swagger.description = 'Forced endpoint.'
#swagger.produces = ["application/json"]
*/
...
/* #swagger.parameters['id'] = {
in: 'path',
description: 'User ID.' } */
const dataId = users.getUser(req.params.id)
...
/* #swagger.parameters['obj'] = {
in: 'query',
description: 'User data.',
type: 'object',
schema: { $ref: "#/definitions/AddUser" }
} */
const dataObj = users.getUser(req.query.obj)
...
if (...)
return res.status(200).send(true) // #swagger.responses[200]
...
return res.status(404).send(false) // #swagger.responses[404]
...
// #swagger.end
}

當然官方也有提供撰寫範例可供參考。

如果你想看我寫的範本,這邊也提供給您參考~

expressSwagger

參考文獻

Liker 讚賞 (拍手)

如果這一篇筆記文章對你有幫助,希望可以求點支持或 牡蠣 鼓勵 (ノД`)・゜・。

Liker 是一個按讚(拍手)的讚賞機制,每一篇文章最多可以按五下拍手,過程你只需要登入,如果你願意按個讚,對於創作者來講是一個莫大的鼓勵與支持。

Google AD

撰寫一篇文章其實真的很花時間,如果你願意「關閉 Adblock (廣告阻擋器)」來支持我的話,我會非常感謝你 ヽ(・∀・)ノ