1. OpenAPI规范

  1. 什么是OpenAPI规范

OpenAPI 规范(OAS),是定义一个标准的、与具体编程语言无关的RESTful API的规范。
OpenAPI 规范使得人类和计算机都能在"不接触任何程序源代码和文档、不监控网络通信"的情况下理解一个服务的作用。
简单来说,OpenAPI文档是一份机器可读的“说明书”,详细描述了你的 API 能做什么,包括:
  • 服务器地址
  • 有哪些可用的URL路径
  • 每个路径支持哪些Action(GET, POST, PUT, DELETE 等)
  • 每个Action需要哪些参数(在路径中、查询字符串中、请求头中等)
  • 请求体应该是什么格式
  • 每个响应可能返回的状态码和对应的数据格式
核心价值:一旦你的 API 被定义在一个标准的 OpenAPI 文档中,整个 API 生命周期中的各种工具都可以基于此文档自动完成工作,极大地提高了效率和规范性。
 
  1. OpenAPI规范术语

  1. OpenAPI 文档

用来定义或描述一个API的YAML(JSON)文档。OpenAPI 文档可以是单个文件也可以被拆分为多个文件,连接的部分由用户自行决定。固定字段:
字段
是否必须
描述
openapi
OPENAPI版本号
info
提供API相关的元数据,如API名称、描述、版本等
servers
Server地址列表
paths
定义API的所有请求路径及Action
components
提供可复用的组件定义,使用$ref引用
security
声明API使用的安全机制
tags
提供更多元数据的一系列标签。
externalDocs
附加文档
  1. 根级别信息

文档的元数据,描述了 API 本身的基本信息。
openapi: 3.0.3  # OpenAPI版本
info:
  title: Agents API       # API的名称
  description: 坐席相关接口
  version: 1.0.0            # API的版本
  contact:
    name: API支持者
    email: icc2.0@msxf.com
servers:
  - url: https://test.example.com/v1  # API的基础地址
    description: test环境服务器
  - url: https://test1.example.com/v1  # AP 的基础地址
    description: test1环境服务器
paths:     # 接下来会定义所有端点
components: # 接下来会定义可重用的组件
tags:
  - name: agents
    description: "坐席相关接口"
  - name: metrics
    description: "指标相关接口"
 
  1. paths- 路径

OpenAPI文档核心,定义了 API 的所有可用URL以及每个URL支持的请求Action。
paths:
  /agents:
    get:
      summary: 获取坐席列表
      operationId: listAgents
      tags:
        - agents
      parameters: # 参数定义
        - name: limit
          in: query
          description: 返回结果的数量限制
          schema:
            type: integer
            default: 10
      responses: # 响应定义'200':description:成功返回坐席列表content:application/json:schema:type:arrayitems:$ref:'#/components/schemas/Agent'
    post:
      summary: 创建一个新坐席
      operationId: createAgent
      tags:
        - agents
      requestBody: # 请求体定义
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Agent'  # 引用components定义的 Agent模型
      responses: ...   # 响应定义
  /agents/{agentId}:
    get:
      summary: 通过ID获取坐席详情
      operationId: getAgentById
      parameters: # 包含路径参数 {agentId}-name:agentIdin:path# 参数位置:path, query, header, cookierequired:truedescription:坐席的IDschema:type:integer
      responses: ...
 
  1. components- 组件

  1. 可重用的对象库,用于避免重复定义。

可以在 paths中通过 $ref来引用这些组件。
components:
  schemas:
    Agent:
      type: object
      required:
        - id
        - name
      properties:
        id:
          type: integer
          format: int64
        name:
          type: string
        status:
          type: string
    Error:
      type: object
      required:
        - code
        - message
      properties:
        code:
          type: integer
          description: 错误代码
        message:
          type: string
          description: 错误描述
          
  1. 全局通用响应结构体

如 200、400、401、403、404、500等通用响应结构,确保全站错误格式统一。
components:
  responses:
    BadRequest:
      description: 400 Bad Request
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          examples:
            invalidParams:
              summary: 参数验证失败
              value:
                code: 400
                message: 请求参数无效
    Unauthorized:
      description: 401 Unauthorized
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          examples:
            tokenExpired:
              summary: Token无效
              value:
                code: 401
                message: 访问令牌已过期
    Forbidden:
      description: 403 Forbidden
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          examples:
            insufficientPermissions:
              summary: 权限不足
              value:
                code: 403
                message: "没有操作权限"
 
  1. OpenAPI Swagger编辑器

 
  1. OpenAPI UI搭建

依赖安装:
yarn add express swagger-ui-express swagger-jsdoc yamljs
yarn add --dev nodemon
通过express启动UI服务:
const express = require('express');
const swaggerUi = require('swagger-ui-express');
const YAML = require('yamljs');

const app = express();
const PORT = process.env.PORT || 3000;

// 加载YAML文件
const swaggerDocument = YAML.load('./swagger.yaml');

app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument));

app.listen(PORT, () => {
  console.log(`服务器运行在端口 ${PORT}`);
  console.log(`Swagger文档: http://localhost:${PORT}/api-docs`);
});
本地Swagger UI:
 
  1. OpenAPI常见规范

  • 路径命名必须使用名词复数形式:资源导向,使用名词而非动词。例如,使用 /users,而不是 /getUsers。
  • 必须正确使用 HTTP 方法:
GET: 查询/获取资源
POST: 创建资源
PUT: 全量更新资源
PATCH: 部分更新资源
DELETE: 删除资源
  • 路径参数必须使用大括号标明:例如 /users/{userId},并在parameters中明确定义 in: path及 required: true。
  • 请求体必须使用 application/json:在 requestBody中指定 content: application/json,并引用定义的 Schema。对于文件上传,需单独使用 multipart/form-data。
  • 必须定义并复用数据模型:所有请求/响应体必须在 components/schemas中定义,并在各处通过 $ref引用,避免重复定义。
  • 模型命名必须使用大驼峰命名法:如 User, CreateUserRequest, UserListResponse。
  • 合理使用枚举:对于固定值的字段(如状态),必须使用 enum明确列出所有可能值。
  • 必须定义全局通用的响应码:在 components/responses中定义如 200、400、401、403、404、500等通用响应结构,确保全站错误格式统一。
  • 每个操作必须包含清晰的摘要和描述:summary简要说明操作,description可提供更详细的上下文或注意事项。
  • 必须为所有操作标记标签:使用 tags对接口进行逻辑分组,便于在生成的文档中分类展示。
 
  1. OpenAPI优势

  1. 与语言无关的标准化接口描述

OpenAPI 规范使用 YAML 或 JSON 格式来描述 API,这两种格式都是机器可读的。这种标准化的描述方式不依赖于任何编程语言,使得不同的工具和系统能够基于同一份规范进行协作。
  1. 自动生成 API 文档

OpenAPI 规范文件可以自动生成交API 文档(如使用 Swagger UI)。文档不仅展示了 API 的URL、参数、请求和响应示例,还允许开发者直接在浏览器中尝试调用 API。
  1. 提升研发效率

利用OpenAPI生成工具(如 Swagger Codegen、OpenAPI Generator),可以根据规范文件自动生成多种编程语言的客户端和服务器代码。前后端可以基于API文档MOCK调试,可以加速前后端的联调进程,并减少手动编写代码可能引入的错误。
  1. 自动化测试

OpenAPI 规范可以用于生成自动化测试用例,验证 API 的实现是否符合规范。可以基于 OpenAPI 规范自动生成测试用例,对 API 进行属性测试,确保 API 的健壮性。
  1. 生态系统和工具支持

OpenAPI 拥有庞大的生态系统,包括各种工具和库,支持从设计、生成、测试到监控的整个 API 生命周期。这些工具包括:
  • Swagger Editor:用于编辑和预览 OpenAPI 规范。
  • Swagger UI:生成交互式 API 文档。
  • Swagger Codegen:生成客户端和服务器代码。
  • Mock Server:根据规范模拟 API 响应。
  • Schemathesis:生成自动化测试用例
 
  1. 基于OpenAPI生成自动化用例

  1. Schemathesis介绍

Schemathesis是一个基于属性测试(Property-based Testing)的API测试工具,专门用于测试符合OpenAPI/Swagger规范的Web API。
 
  1. Schemathesis特点

  1. 属性测试

  • 不同于传统的示例测试,不会提供明确的输入值,不验证明确逻辑。
  • 自动生成大量随机但符合规范的测试数据,包括无效、意外或随机的输入,以测试API的鲁棒性和错误处理能力。
  • 验证 API 的通用属性而非特定场景。
  1. 自动生成测试

基于OpenAPI文档自动生成测试用例,覆盖API的所有端点和参数。
st run --checks all http://api.example.com/openapi.json
  1. 智能断言

  • 响应状态码在定义范围内
  • 响应模式符合 schema
  • 响应内容类型正确
  • 没有服务器错误(500 Server Error)
 
  1. Schemathesis快速开始

  1. 安装

pip install schemathesis

# 验证安装
schemathesis --version
  1. 准备yaml文件

openapi: 3.0.3
info:
  title: 坐席管理 API
  description: 简单的坐席管理接口示例
  version: 1.0.0
  contact:
    name: API 支持
    email: support@example.com

servers:
  - url: http://localhost:8000/api/v1
    description: 开发服务器
  - url: https://api.example.com/v1
    description: 生产服务器

paths:
  /agents:
    get:
      summary: 获取坐席列表
      description: 获取系统中所有坐席的列表,支持分页和过滤
      operationId: getAgents
      tags:
        - 坐席管理
      parameters:
        - name: page
          in: query
          description: 页码
          required: false
          schema:
            type: integer
            minimum: 1
            default: 1
            example: 1
        - name: limit
          in: query
          description: 每页数量
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 20
            example: 20
        - name: active
          in: query
          description: 过滤活跃坐席
          required: false
          schema:
            type: boolean
            example: true
      responses:
        '200':
          description: 成功获取坐席列表
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: true
                  data:
                    type: object
                    properties:
                      agents:
                        type: array
                        items:
                          $ref: '#/components/schemas/Agent'
                      pagination:
                        $ref: '#/components/schemas/Pagination'
                  message:
                    type: string
                    example: "坐席列表获取成功"
              examples:
                success:
                  summary: 成功响应示例
                  value:
                    success: true
                    data:
                      agents:
                        - id: 1
                          name: "张三"
                          email: "zhangsan@example.com"
                          age: 28
                          active: true
                          createdAt: "2024-01-15T10:30:00Z"
                        - id: 2
                          name: "李四"
                          email: "lisi@example.com"
                          age: 32
                          active: true
                          createdAt: "2024-01-16T14:20:00Z"
                      pagination:
                        page: 1
                        limit: 20
                        total: 2
                        pages: 1
                    message: "坐席列表获取成功"
        '400':
          description: 请求参数错误
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                invalid-params:
                  summary: 参数错误示例
                  value:
                    success: false
                    error:
                      code: "INVALID_PARAMS"
                      message: "参数验证失败"
                      details:
                        - field: "limit"
                          message: "必须小于或等于100"
                    message: "请求参数无效"
        '500':
          description: 服务器内部错误
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                server-error:
                  summary: 服务器错误示例
                  value:
                    success: false
                    error:
                      code: "INTERNAL_ERROR"
                      message: "服务器内部错误"
                    message: "系统繁忙,请稍后重试"

components:
  schemas:
    Agent:
      type: object
      required:
        - id
        - name
        - email
      properties:
        id:
          type: integer
          format: int64
          description: 坐席唯一标识
          example: 1
        name:
          type: string
          description: 坐席姓名
          minLength: 1
          maxLength: 50
          example: "张三"
        email:
          type: string
          format: email
          description: 坐席邮箱
          example: "agent@example.com"
        age:
          type: integer
          minimum: 0
          maximum: 150
          description: 坐席年龄
          example: 28
        active:
          type: boolean
          description: 是否活跃
          default: true
          example: true
        createdAt:
          type: string
          format: date-time
          description: 创建时间
          example: "2024-01-15T10:30:00Z"
        updatedAt:
          type: string
          format: date-time
          description: 更新时间
          example: "2024-01-20T08:15:00Z"

    Pagination:
      type: object
      properties:
        page:
          type: integer
          description: 当前页码
          example: 1
        limit:
          type: integer
          description: 每页数量
          example: 20
        total:
          type: integer
          description: 总记录数
          example: 150
        pages:
          type: integer
          description: 总页数
          example: 8

    Error:
      type: object
      properties:
        success:
          type: boolean
          example: false
        error:
          type: object
          properties:
            code:
              type: string
              description: 错误代码
              example: "VALIDATION_ERROR"
            message:
              type: string
              description: 错误信息
              example: "参数验证失败"
            details:
              type: array
              items:
                type: object
                properties:
                  field:
                    type: string
                    example: "email"
                  message:
                    type: string
                    example: "必须是有效的邮箱格式"
        message:
          type: string
          description: 坐席友好的错误信息
          example: "请求参数无效"

  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: JWT token认证
  1. 本地启动Mock API服务

准备nodejs环境,安装prism
yarn global add @stoplight/prism-cli

# 动态模拟接口返回
prism mock openapi.yaml --dynamic
服务启动后检查API正常返回
  1. 使用Schemathesis测试接口

命令行执行:
schemathesis run openapi.yaml --url=http://127.0.0.1
执行结果:
测试报告生成yaml格式:
schemathesis run openapi.yaml --url=http://127.0.0.1 --report vcr --report-vcr-path ./custom-vcr.yaml
 
  1. Schemathesis与pytest集成

集成示例:
import schemathesis

schema = schemathesis.openapi.from_path("./openapi.yaml")

@schema.parametrize()
def test_api_code(case):
    print(case)
    response = case.call(url="http://127.0.0.1")
    assert response.status_code is not None
    assert response.status_code != 500

@schema.parametrize()
def test_api_response(case):
    print(case)
    case.call_and_validate(url="http://127.0.0.1")
测试报告:
 
posted on 2026-03-11 09:43  小海海宁宁  阅读(41)  评论(0)    收藏  举报