Swagger 入门使用

时间:2019-08-21
本文章向大家介绍Swagger 入门使用,主要包括Swagger 入门使用使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

概述

使用 Swagger 解决什么问题, 怎么使用 Swagger, 如何规范 go-swagger 的使用.

背景介绍

为了解决与后端对数据的的强耦合,  使用 HTTP 接口进行解耦.

而 Swagger 一方面可以非常友好的对外展示接口, 文档即接口, 另

一方面可以使用 go-swagger 自动生成部分 server 端代码, 快速实现接口开发. 方便以后可以快速开发 HTTP 服务接口

主要内容

简介

Swagger 是一个简单但功能强大的 API 表达工具。

Swagger 使用 OpenAPI 规范(试图通过定义一种用来描述API格式或API定义的语言,来规范RESTful服务开发过程).

使用 Swagger 生成 API,我们可以得到交互式文档,自动生成代码的 SDK 以及 API 的发现特性等。

wagger 主要包括三部分 Swagger API Spec,描述 Rest API 的语言。Swagger UI,将 Swagger API Spec 以 HTML 页面展现出来的模块。Swagger Editor,Swagger API Spec 的编辑器

为什么使用 swagger

主要是因为工作的核心在实时服务方面.

一方面: swagger能够帮助我们节省编写接口文档的时间,提高我们开发时的效率.

另一方面: 保证文档的即时性,准确性以及一致性, 减少不必要的沟通工作, 文档都是同一份

另外一方面: 使用 go-swagger 自动生成部分代码, 减少写重复代码.

go-swagger 简介

go-swagger 是 Swagger 2.0 的 Go 语言实现。将 swagger 接口文档生成客户端、服务端代码

怎么使用 Swagger

使用步骤

  1. 使用 swagger-editor 定义 API
  2. 使用 swagger-ui 展示 API 定义
  3. 使用 go-swagger 生成代码
  4. 基于代码增加业务处理逻辑

swagger-spec

Swagger 使用 OpenAPI 规范开发 API。后来, SmartBear Software 将 Swagger 规范捐赠给 Linux Foundation,并将规范重命名为OpenAPI规范。 SmartBear 成为OpenAPI Initiative(OAI)的创始成员,该机构以开放和透明的方式管理 OAS 的发展。

简而言之 Swagger 包含了一套 API 规范,并且提供一系列的生态组件
OpenAPI = 规范
Swagger = 实现规范的组件

swagger-ui

除官方提供的 swagger-ui 外, 还有一个Re-Doc, 界面交互我觉得更好一点, 但是存在一点的规范丢失.

go-swagger 生成服务端、客户端代码

swagger generate server --target  --name --spec ../../swagger.yaml 

swagger generate client -f  swagger.yml -A  应用名称 -t 目录

如何自定义 handler

可以在生成代码的restapi.configure_*中手动将handler 的业务逻辑实现, 缺点是对生成的代码有修改, 约束性较高.

参考 kv-store (官方推荐), 每一个 handler 都定义一个 struct.

举例说明

接口列表

重新生成回放

批量查询重新生成回放状态

查询所有在线教师, 包括正在上课的老师以及在线的老师

批量查询连线信息

批量查询回放信息

定时同步session 信息

swagger 接口定义

swagger: '2.0'
info:
  description: '开放 API, 主要用于获取连线相关的信息'
  version: 1.0.0
  title: Swagger Session
  contact:
    name: zhanghaojie
    email: zhanghaojie@iyunxiao.com
externalDocs:
  description: Find out more about Swagger
  url: 'http://swagger.io'
basePath: /v1/session
tags:
  - name:  session
    description: '连线信息'
schemes:
  - http
host: testhfsfd-sessions.haofenshu.com
consumes:
  - application/json
produces:
  - application/json
paths:
  /playbackInfos:
    post:
      tags:
        - session
      summary: '批量获取回放信息'
      description: '如果请求内容中包含不存在的连线 ID, 响应中不会包含此 ID 的任何信息'
      operationId: getPlaybackInfosBySessionIds
      parameters:
        - name: sessionIds
          description: '连线 ID 的数组'
          in: body
          required: true
          schema:
            $ref: '#/definitions/SessionIds'
      responses:
        '201':
          description: '请求成功'
          schema:
            type: object
            properties:
              result:
                type: string
                description: '结果情况, success 代表成功, 其他 代表失败'
                enum:
                  - success
                  - fail
                example:
                  "success"
              msg:
                type: string
                description: '对结果的描述'
                example:
                  "获取成功"
              data:
                type: array
                items:
                  $ref: '#/definitions/PlaybackInfo'
        '500':
          $ref: '#/responses/Standard500ErrorResponse'
  /{sessionId}/playbackStatus/regeneration:
    put:
      tags:
        - session
      summary: '重新生成回放'
      description: '重新生成回放'
      operationId: setPlaybackStatusToRegeneration
      parameters:
        - name: sessionId
          description: '连线 ID'
          required: true
          in: path
          type: string
      responses:
        '201':
          description: '请求成功'
          schema:
            type: object
            properties:
              result:
                type: string
                description: '结果情况, success 代表成功, 其他情况 代表失败'
                enum:
                  - success
                  - sessionNoFound
                  - repeatSubmit
                  - generating
                example:
                  "success"
              msg:
                type: string
                example:
                  "重新生成成功"
        '500':
          $ref: '#/responses/Standard500ErrorResponse'
  /playbackStatuses:
    post:
      tags:
        - session
      summary: '批量获取回放状态信息'
      description: '如果请求内容中包含不存在的连线 ID, 响应中不会包含此 ID 的任何信息'
      operationId: getPlaybackStatusesBySessionIds
      parameters:
        - name: sessionIds
          description: '连线 ID 的数组'
          in: body
          schema:
            $ref: '#/definitions/SessionIds'
      responses:
        '201':
          description: '请求成功'
          schema:
            type: object
            properties:
              result:
                type: string
                description: '结果情况, success 代表成功, 其他 代表失败'
                enum:
                  - success
                  - fail
                example:
                  "success"
              msg:
                type: string
                description: '对结果的描述'
                example:
                  "获取成功"
              data:
                type: array
                items:
                  $ref: '#/definitions/PlaybackStatus'
        '500':
          $ref: '#/responses/Standard500ErrorResponse'
  /teachers/{teacherStatus}:
    get:
      tags:
        - session
      summary: '获取不同状态下所有的老师'
      operationId: getAllTeachersByStatus
      description: 'online 包含 inClass 中的老师'
      parameters:
        - name: teacherStatus
          description: 'online 表示在线的老师, inClass 表示连线中的老师'
          in: path
          required: true
          type: string
          enum:
            - online
            - inClass
      responses:
        '200':
          description: '请求成功'
          schema:
            type: object
            properties:
              result:
                type: string
                description: '结果情况, success 代表成功, 其他 代表失败'
                enum:
                  - success
                  - fail
                example:
                  "success"
              msg:
                type: string
                description: '对结果的描述'
                example:
                  "获取成功"
              data:
                type: array
                items:
                  type: string
        '500':
          $ref: '#/responses/Standard500ErrorResponse'
  /sessionInfosByRange:
    get:
      tags:
        - session
      summary: '同步课堂信息, 通过传入 连线 开始时间的时间区间'
      operationId: getSessionInfosByRange
      parameters:
        - name: start
          in: query
          required: true
          description: '连线 开始时间的起始时间戳(unix 时间戳(毫秒))'
          type: integer
          format: int64
        - name: end
          in: query
          required: true
          description: '连线 开始时间的截止时间戳(unix 时间戳(毫秒))'
          type: integer
          format: int64
      responses:
        '201':
          description: '请求成功'
          schema:
            type: object
            properties:
              result:
                type: string
                description: '结果情况, success 代表成功, 其他 代表失败'
                enum:
                  - success
                  - fail
              msg:
                type: string
                description: '对结果的描述'
              data:
                type: array
                items:
                  $ref: '#/definitions/SessionInfo'
        '500':
          $ref: '#/responses/Standard500ErrorResponse'
  /sessionInfosBySessionIds:
    post:
      tags:
        - session
      summary: '批量查询连线信息'
      description: '如果请求内容中包含不存在的连线 ID, 响应中不会包含此 ID 的任何信息'
      operationId: getSessionInfoBySessionIds
      parameters:
        - name: sessionIds
          description: SessionId's array
          in: body
          required: true
          schema:
            $ref: '#/definitions/SessionIds'
      responses:
        '201':
          description: '请求成功'
          schema:
            type: object
            properties:
              result:
                type: string
                description: '结果情况, success 代表成功, 其他 代表失败'
                enum:
                  - success
                  - fail
              msg:
                type: string
                description: '对结果的描述'
              data:
                type: array
                items:
                  $ref: '#/definitions/SessionInfo'
        '500':
          $ref: '#/responses/Standard500ErrorResponse'
definitions:
  PlaybackStatus:
    type: object
    required:
      - sessionId
      - status
    properties:
      sessionId:
        type: string
        description: '数据库 session 表中的 session 字段'
        example:
          "7210000"
      status:
        type: string
        description: '
        回放状态信息: <br>
          playbackNotGenerated 回放还未生成, 包括需要重新生成, 还未生成 <br>
          sessionNotExist 课程不存在 <br>
          sessionNotFinish 课程正在上课 <br>
          playbackFailedGenerated 回放生成失败, 包括只有语音、只有画图等各种错误情况 <br>
          playbackSuccessGenerated 回放生成成功'
        default: sessionNotExist
        enum:
          - sessionNotExist
          - sessionNotFinish
          - playbackNotGenerated
          - playbackFailedGenerated
          - playbackSuccessGenerated
        example:
          "playbackSuccessGenerated"
  PlaybackInfo:
    type: object
    required:
      - sessionId
    properties:
      sessionId:
        type: string
        description: '回放视频 ID'
        example:
          "7210000"
      status:
        type: string
        description: '
        回放状态信息: <br>
          sessionNotExist 课程不存在 <br>
          sessionNotFinish 课程正在上课 <br>
          playbackNotGenerated 回放还未生成, 包括需要重新生成, 还未生成 <br>
          playbackFailedGenerated 回放生成失败, 包括音频错误等各种错误情况 <br>
          playbackSuccessGenerated 回放生成成功, 存在下载地址, 视频大小 <br>
          playbackNotVideo 老回放, 只有视频地址 没有下载地址'
        default: sessionNotExist
        enum:
          - sessionNotExist
          - sessionNotFinish
          - playbackNotGenerated
          - playbackFailedGenerated
          - playbackSuccessGenerated
          - playbackNotVideo
        example:
          "playbackSuccessGenerated"
      videoUrl:
        type: string
        description: '新回放的下载地址'
        example:
          "http://yx-fudao.ks3-cn-beijing.ksyun.com/testreplayer_data/7210000/7210000.mp4?Expires=1548152332&AWSAccessKeyId=AKLT6GLT4mf1RoiAY5DCcsd_3Q&Signature=zXSJNkX9C3ovtmPYwF3Y2fNcXdY%3D"
      videoSize:
        type: integer
        format: int64
        default: -1
        description: '新回放的文件大小(单位: byte)'
        example:
          1026323
      expire:
        type: integer
        format: int64
        description: '新回放下载地址的过期时间(unix 时间戳(毫秒))'
        example:
          1548507047292
      webUrl:
        type: string
        description: '旧回放的直接播放地址'
        example:
          "testhfsfd-replayer.haofenshu.com/entry?sid=7210000"
  SessionInfo:
    type: object
    required:
      - sessionId
    properties:
      sessionId:
        type: string
        description: '数据库 session 表中的 session 字段'
        example:
          "7210000"
      teacher:
        type: string
        description: '老师的用户名'
        example:
          "muyi"
      student:
        type: string
        description: '学生的用户名'
        example:
          "test014"
      status:
        type: string
        description: '
        回放状态信息: <br>
          playbackNotGenerated 回放还未生成, 包括需要重新生成, 还未生成 <br>
          sessionNotExist 课程不存在 <br>
          sessionNotFinish 课程正在上课 <br>
          playbackFailedGenerated 回放生成失败, 包括只有语音、只有画图等各种错误情况 <br>
          playbackSuccessGenerated 回放生成成功'
        default: sessionNotExist
        enum:
          - sessionNotExist
          - sessionNotFinish
          - playbackNotGenerated
          - playbackFailedGenerated
          - playbackSuccessGenerated
        example:
          "playbackSuccessGenerated"
      classType:
        type: string
        description: '课程类型, UnFormal 代表非正式课, Formal 代表正式课'
        enum:
          - UnFormal
          - Formal
        example:
          "Formal"
      startTime:
        type: integer
        format: int64
        description: '课程开始时间(unix 时间戳(毫秒))'
        example:
          1548085855
      endTime:
        type: integer
        format: int64
        description: '课程结束时间(unix 时间戳(毫秒))'
        example:
          1548067573
  SessionIds:
    type: object
    description: '连线 ID 的数组'
    required:
      - sessionIds
    properties:
      sessionIds:
        type: array
        uniqueItems: true
        minItems: 1
        items:
          type: string
          minLength: 1
          example:
            "7210000"
        example:
          ["7210000","7210001","7210002","7210003","7210004","7210005"]
  Error:
    type: object
    required:
      - message
    properties:
      message:
        type: string
        example:
          "database error"
responses:
  Standard500ErrorResponse:
    description: '服务器内部异常'
    schema:
      $ref: '#/definitions/Error'

接口定义规范

go-swagger 会做部分业务校验, 此时的返回码是RESTful风格 的HTTP Code

在 Swagger 中的描述性话语尽量使用中文. summary 使用简单概述, description 尽可能描述清楚

不必非得遵循 RESTful 风格. HTTP Method 仅使用 GET、POST、PUT 、DELETE 这些常用的方法, HTTP Code 也仅使用常用状态码

接口保证好的扩展性

个人思考

个人思考

为什么使用 Swagger

选用 Swagger 的主要考虑点在代码接口层跟接口文档的统一, 并且我们的主要工作并不是以写接口为主, 因此选用 Swagger 可以方便管理文档与兼顾效率.

Go 常用的 HTTP 框架如 Gin 与 Beego 都提供了对 Swagger 的支持, 但是需要将相应的注释或注解编写到方法上,再利用生成器自动生成说明Swagger文件. 他们将一些不是代码相关的内容注入到代码中, 增加部分冗余.

go-swagger、gin、beego 的区别

gin 在 Go 社区的流行度非常高, 远高于其他. 流行程度可以方便问题的处理. beego 在国内来说是使用的人数也不错, 但从论坛中看出大家开始放弃 Beego, 因为它的大而全. go-swagger 使用的人数还是相当较少, 从官方文档中看到使用go-swagger的一些项目中, 很多是使用它做 Client, 而非 Server.

go-swagger 的默认路由是 naoina's denco, 官方的文档中说明其是一个 ternary search tree, 相对于 gin 的 httprounter 中的 radix tree性能更好. (我也没有测试). beego 相关的路由实现我未找到, 其支持正则匹配. 

go-swagger 对 handler 的管理

个人觉得这是一个很棘手的问题, 如果每个 handler 都写一个 struct 其实现其接口方法, 如果接口越来越多, 导致 main 方法中对 API 注入越来越多, 并且一个接口一个 struct 这种方式, 个人还是觉得非常不优雅的.大家有什么好的方法可以提供建议.

go-swagger 散失代码的灵活性

go-swagger 对 swagger spec 中的校验有实现, 可以说非常的方便, 减少业务代码的冗长. go-swagger 可以支持增加middleware, 进行一些功能扩展.

使用框架必然会散失部分灵活性, 这是一个权衡的问题.

总结

Swagger 结合 go-swagger 可以快速的开发 API 接口, 并且可以实现代码与接口文档的一致, 保证接口的一致. 结合当前项目还是非常棒的选择

参考资料

    1. Swagger Spec 结构
    2. 如何编写基于OpenAPI规范的API文档
    3. API接口管理之道
    4. Go HTTP路由基准测试

原文地址:https://www.cnblogs.com/Zereker/p/11390850.html