目录

    在前后端分离框架中,API文档频繁交接。如果涉及到第三方接口调用,多方合作场景下,API和文档变更可能会更快。为了方便维护API和交接文档,这里给大家推荐一款文档生成工具 - apidoc

    1.apidoc 简介

    apidoc 是一个基于nodejs的API 文档生成工具,从代码注释中提取特定格式的内容,生成API文档。

    目前支持的语言有:C#、C/C++、D、Erlang、Go、Groovy、Java、Javascript、Pascal/Delphi、Perl、PHP、Python、Rust、Ruby、Scala 和 Swift。

    特点:

    • 跨平台,linux、windows、macOS 等都支持。
    • 支持语言广泛。
    • 支持文档版本管理。
    • 支持多个不同语言的多个项目生成一份文档。
    • 输出模板可自定义。

    2. 举个例子

    以Django为例,在views函数中写注释

    def myview(request, id):
        """   
        @api {GET} ci/app/:id/ 获取应用详情
        @apiVersion 1.0.0
        @apiDescription 获取应用详情
        @apiName getAppDetail
        @apiGroup Application
        @apiSuccessExample  请求成功
        HTTP/1.1 200 OK
        {
            "result": true,
            "data": [],
            "code": 0,
            "message": u'成功说明'
        }
        @apiSuccess {Boolean} result true
        @apiSuccess {Array} data  数据列表
        @apiSuccess {Number} code 0
        @apiSuccess {String} message 说明       
        """
    

    生成的API文档

    3. apidoc支持的关键字

    apidoc通过抽取代码注释,根据关键字语法生成API文档。所以,如果想生成理想的API文档,一定要遵循apidoc的相关关键字语法。下面是一个关键字语法的list,{ }表示需要替换的变量,[ ]表示可选参数:

    • @api {method} path [title]。 只有使用@api标注的注释块才会在解析之后生成文档,title会被解析为导航菜单(@apiGroup)下的小菜单 method可以有空格,如{POST GET}
    • @apiGroup name。 分组名称,被解析为导航栏菜单
    • @apiName name。 接口名称,在同一个@apiGroup下,名称相同的@api通过@apiVersion区分,否者后面@api会覆盖前面定义的@api
    • @apiDescription text。 接口描述,支持html语法
    • @apiVersion verison。 接口版本,major.minor.patch的形式
    • @apiIgnore [hint]。 apidoc会忽略使用@apiIgnore标注的接口,hint为描述
    • @apiSampleRequest url。 接口测试地址以供测试,发送请求时,@api method必须为POST/GET等其中一种
    • @apiDefine name [title] [description]。 定义一个注释块(不包含@api),配合@apiUse使用可以引入注释块 在@apiDefine内部不可以使用@apiUse
    • @apiUse name。 引入一个@apiDefine的注释块
    • @apiParam [(group)] [{type}] [field=defaultValue] [description]。请求参数
    • @apiHeader [(group)] [{type}] [field=defaultValue] [description]。头部参数
    • @apiError [(group)] [{type}] field [description]。响应错误时参数
    • @apiSuccess [(group)] [{type}] field [description]。成功时参数, group表示参数的分组,type表示类型(不能有空格),入参可以定义默认值(不能有空格)
    • @apiParamExample [{type}] [title] example。参数请求用例
    • @apiHeaderExample [{type}] [title] example。头部请求用例
    • @apiErrorExample [{type}] [title] example。错误请求用例
    • @apiSuccessExample [{type}] [title] example。成功请求用例 type表示的是example的语言类型, example内容会被直接解析显示。
    • @apiPermission name。 name必须独一无二,描述@api的访问权限,如admin/anyone

    4. 安装配置apidoc

    • 安装apidoc

    这里默认已经安装了nodejs,如果没有安装,请自行下载安装。全局安装apidoc:

    npm  install apidoc -g
    
    • 配置

    配置是可选的,没有配置并不影响文档的生成。只是缺失部分API文档信息而已。在工程的根目录下,创建apidoc.json文件,配置文档的基本信息:

    {
      "name": "项目API文档",
      "version": "1.0.0",
      "description": "项目API文档-说明",
      "title": "项目API文档-title"
    }
    
    • 生成文档

    在apidoc.json所在的目录下,执行命令:

    apidoc -i ./
    

    -i 参数表示输入的目录,默认生成的文档在当前目录下的/doc,也可以通过-o参数指定。

    5. apidoc自动生成

    每次更新代码注释之后,执行一次apidoc -i ./才能看到API文档,比较麻烦。能不能每次修改注释之后,自动生成API文档呢?当然可以。

    • 安装gaze

    gaze是基于nodejs的文件监控项目。

    npm  install gaze -g
    
    • 编写监控代码

    apidoc-watch.js

    var gaze = require('gaze');
    var exec = require('child_process').exec;
    
    function Watch(){
        gaze('./*.*',function(error,watcher){
         this.on('all', function(event, filepath) {
            console.log(filepath + ' was ' + event);
            Geneartion();
          })
        });
    }
    
    function Geneartion(){
        var msg = exec('apidoc -e ./node_modules/')
        msg.stdout.on('data', function (data) {
            console.log('生成Api->' + data);
        });
    
        msg.stderr.on('data', function (data) {
            console.log('生成出错->' + data);
        });
    }
    
    Geneartion();
    Watch();
    console.log('正在监听......');
    
    
    • 执行监控

    只需要更新注释之前,执行一次命令即可。

    node apidoc-watch.js
    

    6. 项目实践建议

    6.1 文档的交接方式

    建议将API文档生成在前端的static目录下,以链接的形式交接,比如: htttp://example.com/static/doc/index.html。

    6.2 后端注释组织方式

    以Django为例,由于apidoc需要的注释量比较大,有两种选择:

    • 一种是将注释直接写在每个views函数中,
    • 一种是单独使用一个文件或文件夹来写注释。

    django中建议skinny controller, fat model,views.py中少些代码,多写注释,第一种方案比较合适。同时,注释和接口实现放在一起,可以降低二次维护学习成本。

    6.3 使用apiDefine和apiUse

    由于前后端,常常会约定固定格式的返回。可以将格式固定的部分,使用apiDefine 定义为一个注释块,在其他地方使用apiUse引用。可以有效减少注释量。

    定义注释块,注意:一个注释块应该被定义为一个单独的注释:

    """
    @apiDefine success
    @apiSuccessExample  请求成功
    HTTP/1.1 200 OK
    {
        "result": true,
        "data": [],
        "code": 0,
        "message": u'成功说明'
    }
    @apiSuccess {Boolean} result true
    @apiSuccess {Array} data  数据列表
    @apiSuccess {Number} code 0
    @apiSuccess {String} message 说明  
    """
    
    """
    @apiDefine error
    @apiErrorExample  请求失败
    HTTP/1.1 40X  error
    {
        "result": false,
        "data": [],
        "code": -1,
        "message": u'失败提示'
    }
    @apiError {Boolean} result false
    @apiError {Array} data  空
    @apiError {Number} code  错误码
    @apiError {String} message 提示
    """
    

    其他地方引用

    def myview(request, id):
        """   
        @api {GET} ci/app/:id/ 获取应用详情
        @apiVersion 1.0.0
        @apiDescription 获取应用详情
        @apiName getAppDetail
        @apiGroup Application
        @apiUse success
        """
    

    6.4 合理使用apiGroup分组

    apiGroup、apiName会被拼接到URL中,比如:static/doc/index.html#api-apiGroup-apiName。给apiGroup、apiName 取个容易理解的名字很重要。合理使用apiGroup,将前端相关的功能聚集在一起,有利于前端理解API的用途。

    7. 参考