又想写一个系列文章了,之因此起这么个标题就是彻底从我自身实践出发,我我的的感受就是,学习一个新知识特别是技术类的,若是只是咬文嚼字,从头至尾的撸一遍文档,下来以后仍是不会达到应用级别,在尝试的时候仍是不断的中断,而后再回头从新看,我以为效率不高。因此,我通常的作法就是直接上手,毕竟如今的前端技术都差很少,大同小异。框架语法+路由+自身的一些前置约束,随便跑一个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代码地址,各位看官,有任何意见均可以提,但愿多多关注多多喜欢。