又想寫一個系列文章了,之因此起這麼個標題就是徹底從我自身實踐出發,我我的的感受就是,學習一個新知識特別是技術類的,若是隻是咬文嚼字,從頭至尾的擼一遍文檔,下來以後仍是不會達到應用級別,在嘗試的時候仍是不斷的中斷,而後再回頭從新看,我以爲效率不高。因此,我通常的作法就是直接上手,畢竟如今的前端技術都差很少,大同小異。框架語法+路由+自身的一些前置約束,隨便跑一個demo感受就差很少能夠上手了。至於更深層次的東西,能夠寫的時候遇到問題了再去深究,這樣的話知識點也掌握得更牢固。html
固然,每一個人的習慣都不一樣,我只是給這一系列文章搞一個噱頭,哈哈😄。前端
容我臭美一下,我看了一些apidoc的文章,我的以爲本身這篇做爲入門級應該是最詳實的了,不管是文章的結構仍是示例代碼,但願朋友們耐心看完😄node
仍是正常操做,雖然我說了喜歡邊寫邊學,可是首先仍是要打開官網去看看基本的知識的,至少你得知道這東西是幹什麼的,基於什麼,有什麼規範等等之類的內容。apiDoc官網介紹了 —— Inline Documentation for RESTful web APIs
。翻譯過來就是「之內聯文檔的形式提供RESTful web APIs」。官網也是話很少說,上來直接就是各類Demo,由於是前端,我只關心JavaScript的了:python
其實apidoc支持不少語言,Java、PHP、python和JavaScript等。git
/**
* @api {get} /user/:id Request User information
* @apiName GetUser
* @apiGroup User
*
* @apiParam {Number} id Users unique ID.
*
* @apiSuccess {String} firstname Firstname of the User.
* @apiSuccess {String} lastname Lastname of the User.
*/
複製代碼
上面就是一個內聯的api文檔,能夠看到,其實apidoc是經過咱們在代碼裏插入必定規範的註解(註釋),而後再經過運行相應的命令去解析,幫助咱們生成RESTful web APIs。這種方式也就意味着約束條件不少,咱們必須嚴格按照約束條件來作,固然好處也是有的,就是不會出錯,約定強也就意味着規範性強。github
前面說過了,約束越強,後面寫起來其實也就越簡單,由於沒什麼創造性的東西,而apidoc的約束也就是各類@apiParam了。web
如上圖,其實也沒想象的那麼多,只要咱們把這些所有掌握了,基本就OK了。npm
既然是邊寫邊學,與其餘文章不一樣的地方就在於,不是一點一點的每個@api按照官方文檔翻譯一下,而是直接拿來用,逐個理解,從示例中去理解的效率要高的多得多得多。因此我準備是優先寫出來一個簡易的demo,而後不斷的加深,而後把全部的apiParam都過一遍,這篇文章就結束了,伴隨着示例代碼,你們看着也會舒服。學起來有代碼也簡單~json
萬變不離其宗,你既然要用它確定得先安裝它。後端
npm install -g apidoc
// 其實我想了一下,安裝在每一個項目裏的devDependencies也是OK的
npm install --save-dev apidoc
複製代碼
由於apidoc最後會給咱們一個靜態文件,咱們能夠進行訪問,那麼關於這個服務的相關配置咱們能夠經過apidoc.json來進行。
這裏有一個前提,就是你得有一個本身的工程,我直接經過node起了一個服務,一個很是簡單的小工程,專門用來放這篇文章的Demo,apidoc-demo,喜歡的能夠給個🌟
// apidoc.json
{
"name": "apidoc-demo",
"version": "1.0.0",
"description": "邊寫邊學系列 —— apidoc",
"title": "apidoc-demo",
"url" : "http://localhost:3333",
"preview-url": "http://localhost:3333/apidoc/index.html" //預覽服務地址
}
複製代碼
name、version、description是基本的配置字段,其餘的看本身的方便來配,用不用得上再說。
OK,激動人心的時刻要到來了,邊寫邊學的興奮之處就在於,你其實還不太理解這個東西的工做原理和過程,經過Demo就把示例跑出來了,這表示你已經能夠成功寫它了,接下來你只須要深刻了解一下就能夠徹底掌握了~
// 咱們在routes/users.js下面寫一個api
/**
* @api {get} /users
* @apiDescription 獲取用戶列表
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {
* "errcode" : 0,
* "message": "",
* "data" : [{
* "name" : "userName",
* "email" : "userEmail"
* }]
* }
* @apiSampleRequest http://localhost:3333/users
* @apiVersion 1.0.0
*/
router.get('/', function(req, res, next) {
res.json({
errcode: 0,
message: '',
data: [
{
name: 'luffy',
email: 'luffy@163.com'
}, {
name: 'naruto',
email: 'naruto@126.com'
}
]
});
});
複製代碼
上面咱們寫好了一個獲取用戶列表的api,而後咱們來生成api文檔。
這裏有兩個前置條件要說明一下
pulic/
目錄下新建apidoc
文件夾apidoc -i routes/ -o public/apidoc/
命令解釋一下,咱們聲稱文檔的命令是
apidoc -i routes/ -o public/apidoc/
,熟悉node的同窗應該都清楚,routes就是後端路由,也就是api的位置,apidoc監聽的是routes/
目錄的全部文件,而後輸出到public/apidoc/
目錄中,這裏其實隨意,你輸出到哪裏均可以,由於它的輸出就是一套靜態文件,帶樣式的html。那麼既然是node服務,我起的靜態服務器就是public,我將生成的文件放到public/apidoc/
文件夾下,項目啓動其實服務也就能夠被訪問了,一箭雙鵰,很方便。因此上面apidoc.json我寫了preview-url: http://localhost:3333/apidoc/index.html
。
由於命令很長,方便往後封裝一下:
// package.json
...
"scripts": {
"start": "DEBUG=apidoc-demo:* nodemon ./bin/www",
+ "apidoc": "apidoc -i routes/ -o public/apidoc/"
}
...
複製代碼
咱們運行yarn apidoc
,控制檯會輸出以下內容表示已經完成
而且/punlic/apidoc/
目錄內也出現了apidoc爲咱們生成的內容:
而後咱們啓動服務yarn start
,訪問http://localhost:3333/apidoc/index.html
。
@api - 定義這是一個apidoc的api
用法:`@api {method} path [title]`
Required,這是必須的,每個apidoc的API文檔必須擁有此ziduan
複製代碼
@apiDescription - 這個api的描述
用法:@apiDescription text
描述這個api是幹什麼的
複製代碼
@apiSuccessExample - 成功示例
用法: @apiSuccessExample [{type}] [title] example
響應成功的返回示例
複製代碼
@apiSampleRequest - 請求地址
用法: @apiSampleRequest url
用來點擊發送示例請求的地址
複製代碼
@apiVersion - api版本號
用法: @apiVersion version
當前api的版本號
複製代碼
上面第一個例子相信你們都跑成功了,並且應該也掌握了幾個基本的字段意義以及如何使用。接下來咱們就進階,擴展一下api參數來豐富咱們的文檔。首先咱們來看看那麼一大串是什麼個東東,看起來真是醜啊。。。
讀一下,大概意思就是接口的位置了,不過這麼長確實有點不美觀了,按照咱們的習慣,/routes/users.js應該就是專門爲User來提供接口的,而且按照以往接口規範,接口也是應該分組的。因此咱們來了,擴展接口功能 —— 分組。
/**
* @api {get} /users
* @apiDescription 獲取用戶列表
+ * @apiGroup User
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {
* "errcode" : 0,
* "message": "",
* "data" : [{
* "name" : "userName",
* "email" : "userEmail"
* }]
* }
* @apiSampleRequest http://localhost:3333/users
* @apiVersion 1.0.0
*/
複製代碼
同時,咱們在上面能夠看到,成功時候的返回,可是返回的數聽說明沒有,繼續擴展,返回數據格式及說明擴展接口功能 - 響應數據規範
/**
* @api {get} /users
* @apiDescription 獲取用戶列表
* @apiName GetUserList
* @apiGroup User
+ * @apiSuccess {array} data 響應數據
+ * @apiSuccess {string} message 響應消息
+ * @apiSuccess {number} errcode 錯誤碼(本身定義,0爲無錯誤)
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {
* "errcode" : 0,
* "message": "",
* "data" : [{
* "name" : "userName",
* "email" : "userEmail"
* }]
* }
* @apiSampleRequest http://localhost:3333/users
* @apiVersion 1.0.0
*/
複製代碼
OK,增長完了,咱們再來從新生成一下文檔並重啓服務yarn apidoc && yarn start
。
能夠看到,咱們擴展的功能按照預期都出現了,至於這兩個的更全面使用,好比響應參數的default-value等等給大家擴展空間,去官網看吧~
上面的示例咱們看到了,擴展了兩個功能,能夠說很接近一個完整的api文檔了,不過既然有successExample,那麼也就應該有errorExample,由於畢竟不是全部請求都能成功,也存在失敗的響應嘛。
還有就是,第一個接口咱們獲取的是全部用戶列表,直接GET /users
就OK了,那麼問題來了,若是有參數該怎麼辦呢,參數應該如何定義呢。因此接下來就寫一個帶參數的接口,咱們來把功能繼續完善。
/**
* @api {get} /users/:id GetUserInfoById
* @apiDescription 獲取用戶列表
* @apiName GetUserById
* @apiGroup User
* @apiParam {Number} id Users unique ID.
* @apiSuccess {Object} data 響應數據
* @apiSuccess {String} message 響應消息
* @apiSuccess {Number} errcode 錯誤碼(本身定義,0爲無錯誤)
* @apiSuccessExample {Json} Success-Response:
* HTTP/1.1 200 OK
* {
* "errcode" : 0,
* "message": "",
* "data" : {
* "id": 0,
* "name" : "userName",
* "email" : "userEmail"
* }
* }
* @apiError {4XX} UserNotFound The <code>id</code> of the User was not found.
* @apiErrorExample {json} Error-Response:
* HTTP/1.1 404 Not Found
* {
* "error": "UserNotFound"
* }
* @apiSampleRequest http://localhost:3333/users/:id
* @apiVersion 1.0.0
*/
router.get('/:id', function(req, res, next) {
const { id } = req.params;
if (!userData.some(item => item.id === parseInt(id, 10))) {
// 不存在直接404
return res.status(404).json({
errcode: 404,
message: `The ${id} of users was not found!`,
data: {}
});
}
// 存在
res.json({
errcode: 0,
message: '',
data: userData.find(item => item.id === parseInt(id, 10))
})
});
複製代碼
代碼雖然有點長,不過大部分都是apidoc的註釋,咱們能夠看到,增長了兩個註解,一個@apiParam
一個@apiErrorExample
,也很簡單,一個是參數,一個是錯誤響應示例。
@apiParam - 參數
用法:@apiParam [(group)] [{type}] [field=defaultValue] [description]
請求參數,類型,能夠包括默認值和參數描述
複製代碼
@apiError - 定義錯誤信息
用法:@apiError [(group)] [{type}] field [description]
定義錯誤類型,如 {4XX}錯誤,{5XX}錯誤
複製代碼
@apiErrorExample - 錯誤響應示例
用法: @apiErrorExample [{type}] [title]
example
錯誤響應的示例
複製代碼
咱們來看一下實際效果:
咱們發送一個錯誤請求,由於3是找不到的,因此返回的是404 Error。成功請求以下:
這裏算是一個小tip吧,也算是踩坑過程經歷到的一個東西,感受挺有意思,能夠這麼用。就是我在使用的時候一直有個疑惑,爲何註解裏只有@apiParam而沒有@apiQuery呢,由於實際場景中仍是有不少query形式的api的,可是說實話真沒發現,雖然RESTful形式的api放在param裏也能夠,不過仍是很疑惑。(若是有大牛給我解釋一下仍是很感激的)
// @apiParam -> @apiQuery
上面那個是個假命題,也就是仍是@qpiParam註解,可是其實是能夠看成query來去作的。仍是以查用戶內容做爲示例
/**
* @api {get} /users/:id GetUserInfoById
* @apiDescription 獲取用戶列表
* @apiParam {Number} id
* ...
* @apiSampleRequest http://localhost:3333/users
* @apiVersion 1.0.0
*/
複製代碼
咱們在上面這個地方;
將原來的: @apiSampleRequest: http://localhost:3333/users/:id
改爲 => @apiSampleRequest: http://localhost:3333/users
而後也會產生一個param爲id字段,此時咱們填寫進去id,在後臺就會將這個param轉換爲query的形式
複製代碼
【注】:官方文檔並無說這麼用,只是我使用起來發現表現是一致的。
到上面爲止,註解基本已經可使用的差很少了,可是有一個問題,若是想寫的很全,每個api上方的註釋會超級的長,怎麼辦呢?這就用到了擴展功能 - @apiDefine和@apiUse
用法:@apiDefine name [title]
[description]
定義公共代碼塊,而後能夠經過@apiUse使用
複製代碼
用法:@apiUse name
使用@apiDefine定義好的代碼塊
複製代碼
咱們仍是舉例說明,好比上面能夠抽離的部分,很明顯,成功返回字段是能夠抽離的,由於成功必定會返回兩個字段errcode,message
,data字段因爲返回內容類型不肯定不是很好肯定,因此不作抽離。因此就抽離一個成功返回字段的代碼塊來使用。
/**
* @apiDefine CommonSuccess 成功響應字段公共部分
* @apiSuccess {Number} errcode The success res code.
* @apiSuccess {Strng} message The res message.
*/
// 在下面使用
/**
* @api {get} /users GetUserList
* @apiDescription 獲取用戶列表
* @apiName GetUserList
* @apiGroup User
+ * @apiUse CommonSuccess
* @apiSuccess {Array} data 響應數據
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {
* "errcode" : 0,
* "message": "",
* "data" : [{
* "id": 0,
* "name" : "userName",
* "email" : "userEmail"
* }]
* }
* @apiSampleRequest http://localhost:3333/users
* @apiVersion 1.0.0
*/
複製代碼
除了上面的註解以外,還剩下的一些其餘可能會用到的註解,這裏順便也說一下。
用法:@apiHeader [(group)] [{type}] [field=defaultValue] [description]
放在req的頭部,通常是用來進行校驗,如jwt
複製代碼
好比,我在獲取全部用戶列表的接口裏要求頭部必須有authorization字段。
/**
* @api {get} /users GetUserList
* @apiDescription 獲取用戶列表
* @apiName GetUserList
* @apiGroup User
+ * @apiHeader {String} Authorization 用戶權限驗證碼
* @apiUse CommonSuccess
* @apiSuccess {Array} data 響應數據
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {
* "errcode" : 0,
* "message": "",
* "data" : [{
* "id": 0,
* "name" : "userName",
* "email" : "userEmail"
* }]
* }
+ * @apiUse InvalidToken
* @apiSampleRequest http://localhost:3333/users
* @apiVersion 1.0.0
*/
複製代碼
如圖所示,在模擬請求的同時會要求將token和header放進去。
用法:@apiPermission name
好比,某些api要求必須管理員才能訪問,或者要求頭部必須anthorization等。
複製代碼
一樣,咱們讓獲取用戶列表增長permission提示:
// 第一步,定義一個token
/**
* @apiDefine token 須要驗證用戶權限
* 須要在header中加入Authorization字段進行用戶權限驗證
*/
// 第二步,使用@apiPermission
@apiPermission token
複製代碼
用法: @apiIgnore [hint]
好比某些方法未完成不想暴露給外面,就是用這個註解
複製代碼
咱們直接在代碼裏新寫一個api而後標記爲@apiIgnore:
/**
* @apiIgnore 沒寫完的POST USER
* @api {post} /users
*/
router.post('/users', function (req, res, next) {
console.log('沒寫完的POST USER');
});
複製代碼
如圖所示能夠看到,咱們的文檔仍然是隻有兩個api,這個post api確實被ignore了。
這裏就不是一個註解了,就是我認爲項目規範裏值得提一點的地方,就是說其實咱們抽離出來的代碼塊是能夠統一管理的,而沒必要要每一個文件都單獨管理。單獨抽離出來我統一放到了/routes/apidoc/common.js
裏面,而後其餘路由文件正常使用就能夠,看起來項目總體就更規範了。仁者見仁智者見智,當項目龐大的時候,還能夠將響應再單獨封裝,這就看本身的須要了~
最後,強調一下,其實我是爲了寫這篇文章隨便起了一個node服務,其實這個服務不適合非常,或者說這個場景不是很合適,爲何呢?由於node+渲染引擎的這種開發模式先後端原本就一我的來寫,並且接口與頁面耦合的很嚴重,一我的去寫其實可能來講沒有必要須要api文檔或者說場景不是很合適。我卻是以爲很適合先後端分離,node端做爲後端,雖然也多是一我的去寫可是可能分離的比較完全~
這個系列的第一篇文章,寫得還算比較流暢,最主要的是我確實是一邊寫代碼一邊學習apidoc一邊寫文章,三位一體感受學的仍是挺深入的。與其說是一篇文章,更不如說是一個記錄過程,不過這個過程我以爲可讓不少小白少走不少彎路,至少有完整的示例代碼,有詳細的學習過程,按部就班,仍是比較適合新手的~
apidoc-demo代碼地址,各位看官,有任何意見均可以提,但願多多關注多多喜歡。