Swager使用手册

[TOC]

前言

 如何编写基于OpenAPI规范的API文档

编写目的

本文介绍如何使用Swagger编写API文档。通过阅读本文,你可以:
  • 了解swagger是什么
  • 掌握使用swagger编写API文档的基本方法

第一章 简介

Swagger
  • Swagger是一个简单但功能强大的API表达工具。
  • 使用Swagger生成的API,我们可以得到交互式文档

OpenAPI规范

OpenAPI规范是Linux基金会的一个项目,试图通过定义一种用来描述API格式或
API定义的语言,来规范RESTful服务开发过程。OpenAPI规范帮助我们描述一个
API的基本信息,比如:
  • 有关该API的一般性描述
  • 可用路径(/资源)
  • 在每个路径上的可用操作(获取/提交…)
  • 每个操作的输入/输出格式

目前V2.0版本的OpenAPI规范(也就是SwaggerV2.0规范)已经发布并开源在
github上。该文档写的非常好,结构清晰,方便随时查阅。关于规范的学习和理解

为啥要使用OpenAPI规范

  • OpenAPI规范这类API定义语言能够帮助你更简单、快速的表述API,尤其是在API的设计阶段作用特别突出

  • 一旦编写完成,API文档可以作为

    • 需求和系统特性描述的根据
    • 前后台查询、讨论、自测的基础
    • 部分或者全部代码自动生成的根据

第二章 swagger 本地环境搭建 基于node

  • 下载Swagger UI(也可以直接下载 zip 文件)

    1
    git clone https://github.com/swagger-api/swagger-ui.git
  • 安装 express

  • 创建一个空文件作为你swagger的本地的文件夹

    1
    mkdir swagger-app
  • 初始化node, 创建package.json

    1
    2
    cd swagger_app	
    npm init -y
  • 安装express

    1
    npm i express --save
  • 创建 index.js

    1
    2
    3
    4
    5
    6
    7
    8
    9
    var express = require('express');
    var app = express();
    app.get('/', function (req, res) {
    res.send('Hello Swagger!');
    });
    // 端口号随意
    app.listen(3333, function () {
    console.log('Swagger_app listening on port 3333!');
    });
  • 在 node_app 中创建空目录 public

    1
    2
    mkdir public
    cd public
  • 修改路由 在index.js 第三行插入下面代码

    1
    app.use('/static', express.static('public'));
  • 把下载好的Swagger UI 文件中的 dist 目录下的文件全部复制到 public 文件夹中

这样就配置好了官方的例子 可以初步了解看一下

官网例子

第三章 如何编写 API文档

好了,我们在本地已经搭建好了swagger2.0的ui
接下来我们就开始了解如何编写api文档

3.1 语言: JSON vs YAML

我们可以选择使用JSON或者YAML的语言格式来编写API文档。但是很多人都建议使用YAML来写,原因是它更简单

YAML语法简介 传送门

3.2 编辑器

可以用 Swagger Editor 在线编辑器

左边编辑API文档,右边实时预览 实时显示报错信息(很赞,超喜欢)

3.3 从简单的yaml的例子开始一步一步开了解swagger2.0如何用yaml编写api文档

1
2
3
4
5
6
7
8
9
10
11
12
13
swagger: "2.0"

info:
version: 1.0.0
title: Simple API
description: A simple API to learn how to write OpenAPI Specification
schemes:
- https
host: simple.api
basePath: /openapi101

paths: {}

上面👆内容分为4个部分

OpenAPI规范的版本号

首先我们要通过一个叫swagger 的属性来声明OpenAPI规范的版本
1
swagger:"2.0"
所以我们了解了OpenApi规范是基于Swagger的

API描述信息

版本、标题、具体描述信息
1
2
3
4
info:
version: 1.0.0
title: Simple API
description: A simple API to learn how to write OpenAPI Specification

API的URL

协议、主机名、根路径
拼接一起就是 https://api.d.qiyukid.com/user,如果有根路径可以加上根路径
1
2
3
4
schemes:
- https
host: api.d.qiyukid.com
# basePath: /user

API的操作(operation)

这个例子中,我们没有写API的操作,用一个YAML的空对象 {} 占了一个位置。

3.4 定义一个API操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#	添加路径,访问/persons
paths:
/persons:
# 添加HTTP的get请求 还有其他的如: post\put\delete
get:
# 信息总结
summary: Gets some persons
# 详细说明
description: Returns a list containing all persons.
# 定义响应(response)类型
# 对于每个方法(操作),都可以在响应中添加任意的http状态码(比如200 ok 或者 404 not found....等等)下面就是添加了简单的 200 描述信息为: A list of Person
responses:
200:
description: A list of Person
# 定义响应的内容
# get/persons这个接口返回一组用户信息,通过响应消息中的 模式(schema)属性来描述具体返回的内容
# 一组用户信息就是一个用户信息对象的数组(arrar),
# 每一个数组元素则是一个用户信息对象(object),
# 该对象包含三个string类型的属性:firstName、lastName、username
schema:
type: array
items:
required:
- username
properties:
firstName:
type: string
lastName:
type: string
username:
type: string

3.5 定义 请求参数 (query parameters)

用户太多,我们不想一股脑全部输出出来。这个时候,分页输出是个不错的选择,
我们可以通过添加请求参数来实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
paths:
/persons:
get:
summary: Gets some persons
description: Returns a list containing all persons. The list supports paging.
#START----------------------------------------------------------------
# 新增的【参数】属性
parameters:
# 添加分页参数
# 添加了两个名字 (name)分别叫pageSize、pageNumber
# 并做了简单的描述以及定义了类型为(integer)
- name: pageSize
in: query
description: Number of personsreturned
type: integer
- name: pageNumber
in: query
description: Page number
type: integer
#END----------------------------------------------------------------
responses:
200:
description: A list of Person
schema:
type: array
items:
required:
- username
properties:
firstName:
type: string
lastName:
type: string
username:
type: string
这样我们就可以通过 get/persons?pageSize=20&pageNumber=2来访问第二页的用户信息了(20条)

3.6 定义 路径参数 (path parameter)

有时候我们想要根据用户名来查找用户信息,这时我们需要增加一个接口操作,比如可以添加一个类似 /persons/{username} 的操作来获取用户信息。
注意,{username} 是在请求路径中的参数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#	与/persons: 同级继续添加一个 persons/{username}:路径 (操作)
# 并定义了一个get方法
# 定义路径参数 {username}
# 因为 {username} 是路径参数,
# 我们需要先像请求参数一样将它添加到parameters属性中,
# 注意名称应该同上面大括号( { } ) 里面的名称一致。
# 并通过 in 这个属性,来表示它是一个路径(path)参数。
persons/{username}:
get:
summary: Gets a person
description: Returns a single person for its username
parameters:
- name: username
in: path
# 定义路径参数时很容易出现的问题就是忘记: required: true ,
# Swagger的自动完成功能中没有包含这个属性定义。
#如果没有写 require 属性,默认值是false。
#也就是说 username 参数时可选的。
#可事⤵️实上,作为路径参数,它是必需的。
required: true
description: The person's username
type: string
# 定义响应消息
# 别忘了获取单个用户信息也需要填写 200 响应消息
# 响应消息体的内容就是之前描述过的用户信息(用户信息列表中的一个元素)
responses:
200:
description: A Person
schema:
required:
- username
properties:
firstName:
type: string
lastName:
type: string
username:
type: string
# API的提供者会对 username 进行校验。
# 如果查无此人,应该返回 404 的异常状态。
# 所以我们再加上 404 状态的响应
404:
description: The Person does not exists.

3.7 定义 消息体参数 (body parameter)

当我们需要添加一个用户信息时,我们需要一个能够提供 post /persons 的API操

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#	在/persons 路径下添加了一个post操作
post:
summary: Creates a person
description: Adds a new person to the persons list.
parameters:
- name: person
# 通过in属性显示说明参数是在body中的。
# 参数的定义参考 get/persons{username}的200响应消息体参数
# 也就是包含用户的lastName、firstName、userName
in: body
description: The person to create.
schema:
required:
- username
properties:
firstName:
type: string
lastName:
type: string
username:
type: string
# 最后也不要忘记了post操作的响应消息
responses:
204:
description: Persons succesfully created.
400:
description: Persons couldn't have been created.
好了,这一章的内容借宿了,总结一下这一章的内容,
基本上我们从零开始用yaml语法建立了一个基础的API文档,
这个文档内容包括:
1、OpenAPI的版本号
2、API文档的信息
    2.1 版本、标题、具体描述信息
    2.2 协议、主机名、根路径
3、定义一个API操作
4、定义 请求参数 (Query Parameters)
5、定义 路径参数 (Path Parameter)
6、定义 消息体参数 (Body Parameter)

第四章 瘦身API文档

上面基本上已经写出了API的一个完整案例,但是我们需要优化一下,因为上面的案例中存在一些重复的内容,我们这一章将把一些重复的内容抽离出来,放到我们学习的新属性:(definitions)中,来简化API文档

4.1 简化数据模型

我们观察后得出 Person的定义出现了几次

在请求参数、路径参数、body参数中都有定义
下面的数据模型,这也是重要很关键的部分
1
2
3
4
5
6
7
8
9
required:
- username
properties:
firstName:
type: string
lastName:
type: string
username:
type: string

可以通过definition属性重新构建一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#	新增(定义)属性	【文档的最末尾】此属性定义的Person可以通过
# $ref: "#/definitions/Person" 引用
# 在定义项中,我们可以立即引用刚才定义好的 Person 来增加另一个 定义 ,Persons。
# Persons 是一个 Person 对象的数组。
# 与之前直接定义的不同之处是,
# 我们增加了一个 引用 (reference)属性,
# 也就是 $ref 来引用 Person 。
definitions:
# 增加一个 Person 对象的定义:
Person:
required:
- username
properties:
firstName:
type: string
lastName:
type: string
username:
type: string
# 新增的Persons的定义,
Persons:
type: array
items:
# 👇引用了一个Person定义增加了另一个 Persons 定义
$ref: "#/definitions/Person"

一旦定义好了 Person ,我们可以把原来在响应消息中相应的定义字段替换掉。

get/persons

修改前:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
responses:
200:
description: A list of Person
schema:
type: array
items:
required:
- username
properties:
firstName:
type: string
lastName:
type: string

修改后:

1
2
3
4
5
6
responses:
200:
description: A list of Person
schema:
$ref: "#/definitions/Persons"

其他重复的以此类推
post /persons 也是如此

4.2 简化响应消息

我们看到了 引用 ($ref)的作用,接下来我们再把它用到响应消息的定义中

原来:

1
2
3
4
5
6
7
8
9
10
11
12
13
responses:
200:
description: A Person
schema:
required:
- username
properties:
firstName:
type: string
lastName:
type: string
username:
type: string

现在:

1
2
3
4
5
responses:
200:
description: A list of Person
schema:
$ref: "#/definitions/Persons"

其他的以此类推
500:
$ref: “#/responses/Standard500ErrorResponse”

4.3 定义可重用的HTTP 500 响应

发生HTTP 500 错误时, 加入我们希望每一个API操作都返回一个带有错误码(error code) 和 描述信息(data或message)的响应,我们可以添加

1
2
3
4
5
6
7
8
500:
description: An unexpected error occured.
schema:
properties:
code:
type: string
message:
type: string

增加一个Error定义

在definitions:下的 Person 同级定义 Error
1
2
3
4
5
6
Error:
properties:
code:
type: string
message:
type: string
修改所有的HTTP 500 状态码的返回状态为
1
2
3
4
5
6
7
8
500:
description: An unexpected error occured.
schema:
#START##########################################################
##################
$ref: "#/definitions/Error"
#END##########################################################
##################

4.4 定义一个可重用的响应消息

上面的文档中,还是有一些重复的内容。我们可以根据OpenAPI规范中的
responses章节的描述,通过定义一个可重用的响应消息,来进一步简化文档。

1
2
3
4
5
6
7
8
9
# 注意这里是在 definitions 同级下 新增了
# responses 且在 responses 中定义了
# Standard500ErrorResponse
# 且使用了Error的定义
responses:
Standard500ErrorResponse:
description: An unexpected error occured.
schema:
$ref: "#/definitions/Error"

注意:响应👆消息中引用了 Error 的定义

4.5 使用定义的响应消息

我们还是通过 引用 ($ref)来使用一个已经定义好的响应消息,比如:

1
2
3
4
5
6
7
8
9
10
11
responses:
200:
description: A list of Person
schema:
$ref: "#/definitions/Persons"
#START##########################################################
##################
500:
$ref: "#/responses/Standard500ErrorResponse"
# END ##########################################################
##################

简化参数定义 通过ref引入

类似数据模型、响应消息的简化,参数定义的简化也很容易

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#START##########################################################
##################

#
parameters:
username:
name: username
in: path
required: true
description: The person's username
type: string
pageSize:
name: pageSize
in: query
description: Number of persons returned
type: integer
pageNumber:
name: pageNumber
in: query
description: Page number
type: integer
# END ##########################################################
##################

在有 parameters 属性的地方引用

1
2
3
parameters:
- $ref: "#/parameters/pageSize"
- $ref: "#/parameters/pageNumber"

自此我们的API基本已经学习完毕

更多高级的swagger2.0 的OpenAPI规范可以去OpenAPI 随时查阅

第五章 以齐语为例,编写第一个API接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
swagger: '2.0'
info: {version: 1.0.0, title: 齐语API文档, description: 齐语项目测试服务器文档API}
schemes: [https]
host: api.d.qiyukid.com
paths:
/user/-wechat/:
get:
summary: 微信登陆
description: 微信登陆
parameters:
- {name: fn, in: query, required: true, description: 微信的回调函数名称, type: string,
default: fetch_user_token}
- {name: code, in: query, required: true, description: 用户id, type: string, default: 1}
- {name: ., in: query, required: true, description: 登陆的tToken, type: string,
default: 81b56308424a2750f91bae6553b138eb}
responses:
'200':
description: 登陆成功 ok
schema: {description: error 0}
'404': {description: 404 not found!}
definitions:
Person:
required: [username]
properties:
firstName: {type: string}
lastName: {type: string}
username: {type: string}
Persons:
type: array
items: {$ref: '#/definitions/Person'}

copy 以上yaml 代码 到 swagger.editor

可以在线调试,

也可以用swagger editor 在线编辑好yamlapi文档。然后以json文件倒入到本地

  • 将导出本地的json文件放到 swagger_app 的 public 目录下
  • 修改swagger的 url 为 /static/qiyu.json
  • 重启 node 服务 , 浏览器中打开 http://localhost:3333/static/index.html 就是刚刚写入的API文档了

第六章 总结

yaml、swaggerUI、swagger editor、OpenAPI

需要有基本的认识。