Super efficient! Swagger-Yapi's Secret

picture

Introduction : I believe that both front-end and back-end development are more or less tortured by interface documentation. The front-end often complains that the interface documentation given by the back-end is inconsistent with the actual situation. The backend also feels that writing and maintaining interface documents will consume a lot of energy, and it is often too late to update. In fact, whether the front-end calls the back-end or the back-end calls the back-end, a good interface document is expected. However, with the passage of time and the iteration of versions, the interface documentation is often unable to keep up with the code, and it is even more likely that the previous classmates left without clear handover of the interface documentation, leaving behind a heavy and complicated project, which is extremely difficult to re-evaluate. No less than writing it from scratch. So it's not enough to just regulate everyone by coercion. We studied the way to get through from Swagger to Yapi. With it, we can do that every time we finish writing the code, we only need to modify the comments by the way, and then submit, and Yapi can automatically change our interface document.

The full text is 8199 words, and the estimated reading time is 21 minutes.

1. Introduction to Swagger

Swagger is a canonical and complete framework for generating, describing, invoking and visualizing RESTful web services. You just need to define the interface and interface-related information according to its specification. Through a series of projects and tools derived from Swagger, it is possible to generate interface documents in various formats, generate client and server codes in multiple languages, and online interface debugging pages, etc.

In this way, according to the new development mode, when developing a new version or an iterative version, you only need to update the Swagger description file, and the interface document and client-side server code can be automatically generated, so that the calling-side code, server-side code and interface can be achieved. Documentation consistency.

2. Swagger build

The following steps build on an environment that already has the ability to run go successfully.

You can see the most complete tutorials on the go-swagger official tutorial, and those who are capable can go directly to the official tutorial.

2.1 ►Installation

picture

All the above download methods are feasible, but in order to be compatible with all our situations, so choose this and download the code directly.

picture

To simplify the command, it actually does two things:

1. The code of clone go-swagger;

2. Add swaager to GOROOT.

mkdir DownLoad
cd DownLoad
git clone https://github.com/go-swagger/go-swagger
cd DownLoad/go-swagger-master/cmd/swagger/
go install .

Verify that it was successful:

[work@hangchuang /]$ swagger -h
Usage:
  swagger [OPTIONS] <command>

Swagger tries to support you as best as possible when building APIs.

It aims to represent the contract of your API with a language agnostic description of your application in json or yaml.


Application Options:
  -q, --quiet                  silence logs
      --log-output=LOG-FILE    redirect logs to file

Help Options:
  -h, --help                   Show this help message

Available commands:
  diff      diff swagger documents
  expand    expand $ref fields in a swagger spec
  flatten   flattens a swagger document
  generate  generate go code
  init      initialize a spec document
  mixin     merge swagger documents
  serve     serve spec and docs
  validate  validate the swagger document
  version   print the version

2.2 ►Build

  • 这一部分全部都是关于swagger的用法的,先来个最简单的,接口注释,把样例上面的注释放复制到接口上方:

picture

picture

  • 样例文档注释:

picture

  • 运行swagger,生成接口文档

    命令:swagger generate spec -o ./swagger.json

picture

  • 启动swagger服务,进入接口文档页面

    命令:swagger serve --no-open swagger.json

picture

三、Swagger规范

Swagger注释的规范以及用法如下。

3.1►swagger:meta

简介:swagger:meta 是你的所有的API的概要,我们用它来形成我们的API文档的开头介绍。

// Go-Swagger API.(title)
//
// 这是我们的测试API (description)
//
//      Terms Of Service:
//     there are no TOS at this moment, use at your own risk we take no responsibility
//
//     Schemes: http, https
//     Host: localhost
//     BasePath: /go-swagger/test
//     Version: 0.0.1
//     License: MIT http://opensource.org/licenses/MIT
//     Contact: Zhubangzheng<[email protected]> [email protected]
//
//     Consumes:
//     - application/json
//     - application/xml
//
//     Produces:
//     - application/json
//     - application/xml
//
//     Security:
//     - api_key:
//
//     SecurityDefinitions:
//     api_key:
//          type: apiKey
//          name: KEY
//          in: header
//     oauth2:
//         type: oauth2
//         authorizationUrl: /oauth2/auth
//         tokenUrl: /oauth2/token
//         in: header
//         scopes:
//           bar: foo
//         flow: accessCode
//
//     Extensions:
//     x-meta-value: value
//     x-meta-array:
//       - value1
//       - value2
//     x-meta-array-obj:
//       - name: obj
//         value: field
//
// swagger:meta
package test

注意:注释的结尾 swagger:meta和package之间不能有空行,否则无法被swagger识别。

注解用法:

picture

3.2►swagger:route

swagger:route 是最主要的一个注释参数,是你的单个API接口的详细信息。

格式:swagger:route [method] [path pattern] [tag1 tag2 tag3] [operation id]

[method]和 [path pattern]必选,后面的[tag]根据你自己决定,首先是你当前接口的tag,然后再考虑加上其他。最后的[operation id]是你的方法的唯一标识,如果仅是作为一个接口文档可以不填,但是它在很多地方都被用作方法名。例如用于客户端生成的方法。

 // ServeAPI serves the API for this record store
func ServeAPI(host, basePath string, schemes []string) error {
  // swagger:route GET /{id}/checkout SwaggerTest swagger_test_checkout
  //
  // Swagger测试接口
  //
  // 用于Swagger测试
  //
  //     Consumes:
  //     - application/json
  //     - application/x-protobuf
  //
  //     Produces:
  //     - application/json
  //     - application/x-protobuf
  //
  //     Schemes: http, https, ws, wss
  //
  //     Deprecated: true
  //
  //     Security:
  //       api_key:
  //       oauth: read, write
  //
  //     Responses:
  //       default: genericError
  //       200: someResponse
  //       422: validationError
    mountItem("GET", basePath+"/{id}/checkout", nil)
}

Response和后面定义的swagger:response对应。

picture

3.3►swagger:patameters

swagger:parameters 是接口的参数注释

格式:swagger:parameters [operationid1 operationid2],parameters 通过[operation id]和route绑定。

参数的玩法很多,但是基本都用不上详细可以在官方文档查看swagger:parameters。

因为我们主要使用GET、POST,而官网只介绍了GET方法,内网外网对于swagger:parameters注解的POST的用法介绍甚少,因此在这里介绍GET和POST的主要玩法即可。

// swagger:parameters swagger_test_checkout 
type SwaggerTest struct {
  // SwaggerTest接口测试参数1 (description)
  // required: true(是否必须)
  // in: query(参数所在的位置)
    ID uinat64 `json:"id"`
}

重点:GET方法的 in 注释 可接 query、header、cookie、path ,不同情况自定。

以上就是我们声明一个GET的参数的必要注释,其他都是非必要,如下图,可以根据自己的具体情况添加。

picture

  • POST:
// swagger:parameters swagger_test_checkout 
type SwaggerTest struct {
  // SwaggerTest接口测试参数1 (description)
  // required: true(是否必须)
  // in: formData(参数所在的位置)
    ID uinat64 `json:"id"`
}

POST方法,参数的位置不在body,换句话说不能 in:body,而是要使用 in:formData,这样的格式导入到yapi之后才会出现在body里,且在本地的swagger ui中也才会正确显示。还有一点需要注意就是建议把swagger:route处的Consumes设置成 multipart/form-data,即:

  // ServeAPI serves the API for this record store
func ServeAPI(host, basePath string, schemes []string) error {
  // swagger:route GET /{id}/checkout SwaggerTest swagger_test_checkout
  //
  // Swagger测试接口
  //
  // 用于Swagger测试
  //
  //     Consumes:
  //     multipart/form-data
  //
  //     ......
    mountItem("GET", basePath+"/{id}/checkout", nil)
}

格式:swagger:response [response name] ,response 通过[response name]和route处定义的response绑定。

响应注释和参数的用法基本一样swagger:response,这里不需要赘述,直接举例。

// A ValidationError is an error that is used when the required input fails validation.
// swagger:response validationError
type ValidationError struct {
    // The error message
    // in: body
    Body struct {
        // The validation message
        //
        // Required: true
        // Example: Expected type int
        Message string
        // An optional field name to which this validation applies
        FieldName string
    }
}

重点:以上的用法是response的基础用法,但是实际上并不符合很多公司内部的结构定义,所以下面会讲真正的灵活且实用的用法。

1、swagger:response 可以出现在任意结构体上。 不需要专门找到我们的response层,或者甚至没有response层的,而是每一个接口都定义了一个专门的response,最后再统一用interface处理,从而导致我们在历史项目里加上swagger异常困难。

例如:

// SwaggerTestResponse
// swagger:response test_res
type SwaggerTestResponse struct {
    // The error message
    // in: body
    Body struct {
        // The validation message
        //
        // Required: true
        // Example: Expected type int
        Message string
        // An optional field name to which this validation applies
        FieldName string
    }
}

注意::必须严格按照格式,Response结构体下嵌套一个Body结构体,也就是说如果是我们的历史项目,就得在Response外再包一层。例如:这是一正在是用的项目的Response返回,我们在上方加上swagger:response,后面跟上它的唯一id,test,在接口的返回处使用。

// Test
// swagger:response old_api_resp
type OldAPIRes struct {
   // Test
   // in: body
   ID uint64
   Name string
   Time string
}
  // ServeAPI serves the API for this record store
func ServeAPI(host, basePath string, schemes []string) error {
  // swagger:route GET /{id}/checkout SwaggerTest swagger_test_checkout
  //
  // Swagger测试接口
  //
  // 用于Swagger测试
  //
  //     Consumes:
  //     - multipart/form-data
  //     Schemes: http
  //     Responses:
  //       200: old_api_resp
    mountItem("GET", basePath+"/{id}/checkout", nil)
}

然后我们生成swagger.json,发现所有参数都被定义在了header下,而这些返回参数实际上应该位于body中,否则就无法被swagger ui和yapi识别。

picture

换句话说 swagger的in:body只识别结构体内嵌套的结构体,为了迎合swagger的识别要求,我们对结构进行改造,换成下面这种写法,就可以被识别在body里了。

// Test
// swagger:response old_api_resp
type OldAPIRes struct {
   // Test
    // in: body
   Body struct {
     ID uint64
     Name string
      Time string
    }
}

上面这种写法其实很不方便,所有的接口的Response下都要多加一层Body,这是不合理的,Swagger只是注释,不应该侵入代码,除非原有的结构就是如此,否则不推荐上面的格式。

2、进阶版swagger:model: 解决了上面的痛点,真正做到了灵活好用。

swagger:model其实也是一个swagger规范,用法非常灵活,详细的用法会在后面介绍,这里就提出用model解决response的方法。

Response的注释修改:

// swagger:model old_api_resp
type OldAPIRes struct {
   ID uint64
   Name string
   Time string
}

Route注释修改:

// ServeAPI serves the API for this record store
func ServeAPI(host, basePath string, schemes []string) error {
  // swagger:route GET /{id}/checkout SwaggerTest swagger_test_checkout
  //
  // Swagger测试接口
  //
  // 用于Swagger测试
  //
  //     Consumes:
  //     - multipart/form-data
  //     Produces:
  //     - application/json
  //     Schemes: http
  //     Responses:
  //       200: body:old_api_resp
    mountItem("GET", basePath+"/{id}/checkout", nil)

命令修改,-m是扫描model:

swagger generate spec -m -o ./swagger.json 

重新生成,然后搞定。

四、Swagger-Yapi

Yapi一个高效、易用、功能强大的API管理平台。

picture

为什么要打通Swagger到Yapi呢?理由很简单。Swagger的SwaggerUI远没有Yapi功能全面,而Yapi能支持导入Swagger.json格式的接口文档,Swagger的便利性和Yapi的全面性,我们把二者结合,从而实现更优的结果。

4.1►Nginx搭建

经过上面的步骤我们应该已经在本地生成了我们接口的Swagger.json,而Yapi已经支持了手动导入和自动导入两种方式。

手动导入:

picture

自动导入:

picture

我们需要的是什么?我们需要的是每次Swagger更新之后,Yapi都会自动更新我们的接口,那么我们自然需要使用Yapi的自动导入,因此我们只需要在自己的机器上搭建一个Nginx来做静态文件代理,就能实现。

下载并安装nginx:

sudo yum install nginx -y

安装完成后查看:

rpm -qa | grep nginx

启动nginx

sudo systemctl start nginx

或是

sudo service nginx start

查看nginx状态

sudo systemctl status nginx

或是

sudo service nginx status

4.2►代理文件

进入nginx目录

cd /etc/nginx/

在conf.d目录下新增需要代理的端口

data映射的目录根据自己的实际情况,即swagger.json所在目录的位置而定。

cd conf.d/
vim yapi.conf
server {
    listen       8888;
    server_name  localhost;

    location /data/ {
       alias '/home/work/Swagger/swagger-yapi/swagger-json/';
    }
}

重启nginx

sudo systemctl restart nginx

sudo service nginx restart

4.3►Yapi自动同步

ip对应你自己的机器ip。

ip地址可以通过以下命令查看:

hostname -i

picture

如果被提示了:

picture

说明路径不对,可以把地址输入浏览器访问,自己调整到正确即可。

五、结语

Swagger还有很多的用法,光是通过swagger -h命令就能看到很多用法,而它的注释的用法也有很多,针对不同语言也有不同的写法。同理,Yapi作为一款功能强大的API管理平台也是一样的有很多的用法,比如在线mock接口等等。本文仅作为一个快速上手入门swagger到yapi的方法,通道搭建好之后,更多的用法就可以各位同学自己去挖掘。

————————END————————

推荐阅读:

百度直播iOS SDK平台化输出改造

百度APP 基于Pipeline as Code的持续集成实践

Go 语言使用 MySQL 的常见故障分析和应对方法

Analysis of the Wallet System Architecture of Baidu Trading Platform

Data modeling application based on wide table

Design and Exploration of Baidu Comments Center

Data visualization platform based on template configuration

Guess you like

Origin juejin.im/post/7116729520681549854