← 编程返回顶部

OpenAPI(Swagger)

1. 基本概念

OpenAPI Specification(OAS)是一套用于描述 HTTP API 的标准规范,可以使用 YAML 或 JSON 格式定义 API。

OpenAPI 文档描述了接口的路径、请求参数、请求体、响应数据、认证方式及数据模型等内容。

OpenAPI、Swagger 和 Schema 的区别

概念说明
OpenAPI描述 HTTP API 的标准规范
Swagger UI根据 OpenAPI 文档生成交互式 API 文档
Swagger Editor编辑和验证 OpenAPI 文档
Swagger Codegen根据 OpenAPI 文档生成客户端或服务端代码
Schema描述 API 请求、响应及数据结构的模式定义

OpenAPI 本身不是 API 框架,也不负责执行 HTTP 请求,而是提供一份机器可读的 API 契约。

典型工作流程:

Django REST Framework
         ↓
drf-spectacular
         ↓
OpenAPI Schema (YAML / JSON)
         ↓
    ┌────┴───────┐
    ↓            ↓
Swagger UI      Orval
    ↓            ↓
API 文档       TypeScript 类型
              API Client / Hooks

通过这种方式,前后端可以共享同一份 API 定义,减少接口字段不一致的问题。

2. OpenAPI 文档结构

OpenAPI 文档的主要对象:

对象作用是否必需
OpenAPI Object根对象,包含整个 API 定义是
Info ObjectAPI 名称、版本、描述等元数据是
Paths ObjectAPI 路径与 HTTP 操作是
Servers ObjectAPI 服务器地址否
Components Object可复用的 Schema、参数、响应等否
Tags Object对接口进行逻辑分组否
ExternalDocs Object外部文档链接否
Security Requirement Object声明 API 的安全认证要求否

注意:security 是 OpenAPI 根对象或 Operation Object 中的字段,不是与 paths、components 同级的独立顶层对象名称。

OpenAPI 3.0 的最小文档:

openapi: 3.0.3

info:
  title: Example API
  version: 1.0.0

paths: {}

OpenAPI Object

完整结构示例:

openapi: 3.0.3

info:
  title: Example API
  description: Example REST API
  version: 1.0.0

servers:
  - url: https://api.example.com/v1

tags:
  - name: users
    description: User management

paths:
  /users:
    get:
      tags:
        - users
      summary: Get users
      operationId: listUsers
      responses:
        "200":
          description: Successful response

components:
  schemas: {}

security: []

其中,openapi 表示 OpenAPI 规范版本,而 info.version 表示 API 自身的版本。

3. Info Object

info 定义 API 的基本信息。

info:
  title: Example API
  description: API documentation example
  version: 1.0.0

  termsOfService: https://example.com/terms

  contact:
    name: API Developer
    url: https://example.com
    email: developer@example.com

  license:
    name: Apache 2.0
    url: https://www.apache.org/licenses/LICENSE-2.0
字段作用
titleAPI 标题
descriptionAPI 描述,支持 Markdown
versionAPI 版本
termsOfService服务条款
contact联系方式
license许可证信息

其中 title 和 version 是必需字段。

4. Servers Object

servers 描述 API 的服务器地址。

可以指定多个服务器:

servers:
  - url: https://dev.example.com/api/v1
    description: Development

  - url: https://staging.example.com/api/v1
    description: Staging

  - url: https://api.example.com/api/v1
    description: Production

使用服务器变量

servers:
  - url: https://{environment}.example.com/api/v{version}
    variables:
      environment:
        default: api
        enum:
          - api
          - dev
          - staging

      version:
        default: "1"
        enum:
          - "1"
          - "2"

variables 允许使用变量定义服务器地址,避免为不同环境重复书写相似配置。

5. Paths Object 与 Operation Object

paths 定义 API 的路径,每个路径包含一个或多个 HTTP 操作。

例如:

paths:
  /users:
    get:
      summary: Get users
      operationId: listUsers
      responses:
        "200":
          description: Success

    post:
      summary: Create user
      operationId: createUser
      responses:
        "201":
          description: Created

  /users/{userId}:
    get:
      summary: Get user
      operationId: getUser
      parameters:
        - name: userId
          in: path
          required: true
          schema:
            type: integer
      responses:
        "200":
          description: Success

Operation Object 的常用字段

字段作用
tags接口分组
summary接口简短描述
description接口详细描述
operationId接口唯一标识
parametersPath、Query、Header、Cookie 参数
requestBodyHTTP 请求体
responsesHTTP 响应定义
security覆盖全局认证要求
deprecated标记接口是否弃用
servers覆盖服务器地址
callbacks描述由 API 提供方发起的回调
externalDocs外部文档

其中 responses 是 Operation Object 的必需字段。

operationId

operationId: getUserProfile

operationId 必须在整个 OpenAPI 文档中保持唯一。

代码生成工具通常利用它生成函数名称。

例如,Orval 可能根据:

operationId: getUserProfile

生成:

getUserProfile();
useGetUserProfile();

具体生成结果取决于 Orval 配置。

因此,建议使用稳定、明确且符合编程命名习惯的 operationId。

6. Parameters Object

parameters 用于描述请求参数。

共有四种位置:

in参数位置示例
pathURL 路径/users/{userId}
query查询字符串?page=2
headerHTTP HeaderX-Request-ID
cookieCookiesessionid

Path Parameter

parameters:
  - name: userId
    in: path
    required: true
    description: User ID
    schema:
      type: integer

对于 in: path,required 必须是 true。

Query Parameter

parameters:
  - name: page
    in: query
    required: false
    schema:
      type: integer
      minimum: 1
      default: 1

  - name: search
    in: query
    required: false
    schema:
      type: string

对应请求:

GET /users?page=2&search=Alice

Parameter 常用字段

字段作用
name参数名称
in参数所在位置
description参数描述
required是否必填
deprecated是否弃用
schema参数的数据结构及验证约束
example参数示例值
style参数序列化方式
explode控制数组或对象参数如何展开
allowEmptyValue是否允许空值,主要针对 Query 参数

数组参数的序列化

parameters:
  - name: ids
    in: query
    style: form
    explode: true
    schema:
      type: array
      items:
        type: integer

对应:

GET /users?ids=1&ids=2&ids=3

如果设置:

style: form
explode: false

则通常序列化为:

GET /users?ids=1,2,3

7. Request Body Object

requestBody 描述客户端发送的数据。

通常用于 POST、PUT、PATCH 等请求。

requestBody:
  required: true
  description: User information
  content:
    application/json:
      schema:
        type: object
        required:
          - username
          - email
        properties:
          username:
            type: string
          email:
            type: string
            format: email
          password:
            type: string
            format: password
      example:
        username: johndoe
        email: john@example.com
        password: example-password

parameters 与 requestBody 的区别

比较parametersrequestBody
作用描述独立请求参数描述请求体
位置path/query/header/cookieHTTP Body
数据结构通常为单个参数定义 Schema可以定义完整对象
常见用途GET 查询、路径参数POST、PUT、PATCH 请求

注意:HTTP 并不绝对禁止 GET 请求携带 Body,但 GET Body 没有普遍定义的请求语义;OpenAPI 3.0 也不支持以常规方式定义 GET requestBody。

多种媒体类型

requestBody:
  content:
    application/json:
      schema:
        $ref: "#/components/schemas/User"

    application/x-www-form-urlencoded:
      schema:
        $ref: "#/components/schemas/User"

content 可以定义多种媒体类型,包括 JSON、表单数据及文件上传。

8. Responses Object

responses 描述 API 在不同 HTTP 状态码下的响应。

responses:
  "200":
    description: Successful response
    content:
      application/json:
        schema:
          $ref: "#/components/schemas/User"

  "400":
    description: Invalid request
    content:
      application/json:
        schema:
          $ref: "#/components/schemas/Error"

  "404":
    description: User not found

  "500":
    description: Internal server error

常见状态码:

状态码含义
200请求成功
201成功创建资源
202请求已接受,可能异步处理
204请求成功,无响应体
400请求参数错误
401缺少有效认证凭据
403禁止访问
404资源不存在
409资源状态冲突
422请求内容无法处理
500服务器内部错误

无响应体

对于 204 No Content:

responses:
  "204":
    description: Successfully deleted

不需要定义 content。

默认响应

responses:
  "200":
    description: Success

  default:
    description: Unexpected error

default 可以描述其他未单独列出的响应情况。

9. Components Object

components 是 OpenAPI 的可复用组件容器。

主要包含:

字段作用
schemas可复用的数据模型
parameters可复用的请求参数
responses可复用的响应
requestBodies可复用的请求体
headers可复用的响应头定义
examples可复用的示例
securitySchemes认证机制定义
linksAPI 操作间的关系
callbacks可复用的回调

定义 Schema

components:
  schemas:
    User:
      type: object
      required:
        - id
        - username
      properties:
        id:
          type: integer
        username:
          type: string
        email:
          type: string
          format: email

定义可复用参数

components:
  parameters:
    PageParam:
      name: page
      in: query
      schema:
        type: integer
        minimum: 1
        default: 1

定义可复用响应

components:
  responses:
    NotFound:
      description: Resource not found
      content:
        application/json:
          schema:
            type: object
            properties:
              detail:
                type: string

10. $ref:组件引用

$ref 用于引用已经定义的组件,减少重复代码。

例如:

paths:
  /users:
    get:
      operationId: listUsers
      parameters:
        - $ref: "#/components/parameters/PageParam"
      responses:
        "404":
          $ref: "#/components/responses/NotFound"

Schema 引用:

schema:
  $ref: "#/components/schemas/User"

引用路径:

#/components/schemas/User

含义是引用当前文档中的:

components
  └── schemas
        └── User

$ref 也支持引用外部文件或 URL 中的定义。

在 OpenAPI 3.0 中,Reference Object 的其他兄弟字段通常会被忽略,因此不建议直接在 $ref 旁边添加 description 等字段来覆盖原始定义。

11. Schema Object:数据模型

Schema Object 用于描述数据类型、字段及验证规则。

OpenAPI 3.0 的 Schema 基于 JSON Schema 的一个扩展子集,而不是完整支持所有 JSON Schema 关键字。

常见数据类型

类型含义常用 format
string字符串date、date-time、email、uuid、binary
integer整数int32、int64
number数值float、double
boolean布尔值—
array数组—
object对象—

format 是对基本类型的进一步描述,具体校验行为取决于使用的工具。

完整 Schema 示例

components:
  schemas:
    Product:
      type: object
      required:
        - id
        - name
        - price
      properties:
        id:
          type: integer
          format: int64
          readOnly: true

        name:
          type: string
          minLength: 1
          maxLength: 100

        description:
          type: string
          nullable: true

        price:
          type: number
          minimum: 0

        category:
          type: string
          enum:
            - electronics
            - books
            - clothing

        tags:
          type: array
          items:
            type: string

        metadata:
          type: object
          additionalProperties: true

常用验证字段

字段说明
required必填属性列表
nullable是否允许 null(OpenAPI 3.0)
default默认值描述
enum限定允许的值
minimum / maximum数值范围
minLength / maxLength字符串长度限制
pattern正则表达式约束
minItems / maxItems数组元素数量限制
uniqueItems数组元素是否唯一
additionalProperties是否允许额外对象属性
readOnly只读字段
writeOnly只写字段
deprecated标记字段已弃用

required 与 nullable 的区别

type: object
required:
  - name
properties:
  name:
    type: string
    nullable: true
  • required:要求对象中必须存在该字段。
  • nullable:允许字段值为 null。

因此,这个示例要求必须提供 name,但允许其值为 null。

不写在 required 列表中的字段表示可以省略,并不自动意味着允许 null。

12. allOf / oneOf / anyOf

OpenAPI 支持使用组合关键字构建复杂数据结构。

关键字含义
allOf必须满足全部 Schema
oneOf必须恰好满足一个 Schema
anyOf满足至少一个 Schema
not不满足指定 Schema

allOf:组合 Schema

components:
  schemas:
    Pet:
      type: object
      required:
        - name
      properties:
        name:
          type: string

    Dog:
      allOf:
        - $ref: "#/components/schemas/Pet"
        - type: object
          properties:
            breed:
              type: string

Dog 同时满足 Pet 和新增的字段约束。

allOf 常用于组合数据模型,但并不意味着编程语言层面的面向对象继承。

oneOf:多个可能的数据模型

schema:
  oneOf:
    - $ref: "#/components/schemas/Dog"
    - $ref: "#/components/schemas/Cat"

表示数据必须恰好符合其中一个 Schema。

如果需要区分不同对象类型,可以结合 discriminator 使用。

13. Security Schemes

OpenAPI 使用 components.securitySchemes 定义认证机制,再通过 security 声明接口需要的认证方式。

Bearer Token(常用于 JWT)

components:
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT

security:
  - BearerAuth: []

对应 HTTP 请求:

Authorization: Bearer <token>

bearerFormat: JWT 主要是文档提示,并不意味着 OpenAPI 自动验证 JWT。

API Key

components:
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key
components:
  securitySchemes:
    SessionAuth:
      type: apiKey
      in: cookie
      name: sessionid

这种方式描述通过 Cookie 传递的凭据,但实际 Session 验证仍由后端完成。

CSRF Token 也不能仅通过定义 securitySchemes 就获得防护能力。

为单个接口覆盖认证

paths:
  /public:
    get:
      security: []
      responses:
        "200":
          description: Success

security: [] 表示移除该操作继承的全局安全要求。

14. Tags 与 ExternalDocs

Tags:接口分组

tags:
  - name: users
    description: User management

  - name: products
    description: Product management

paths:
  /users:
    get:
      tags:
        - users
      responses:
        "200":
          description: Success

Tags 主要用于 Swagger UI 等文档工具的接口分类。

ExternalDocs:外部文档

externalDocs:
  description: Additional API documentation
  url: https://example.com/docs

可以在顶层、操作或部分 Schema 定义中提供外部文档信息。

15. 文件上传:multipart/form-data

文件上传通常使用 multipart/form-data。

paths:
  /users/avatar:
    post:
      summary: Upload avatar
      operationId: uploadAvatar

      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              required:
                - file
              properties:
                file:
                  type: string
                  format: binary

      responses:
        "200":
          description: Upload successful

重点:

type: string
format: binary

表示二进制文件字段。

对于 Django REST Framework,通常可以结合:

from rest_framework.parsers import MultiPartParser

处理上传请求。

16. drf-spectacular 与 Django REST Framework

drf-spectacular 可以根据 DRF 的 View、Serializer、URL 等信息自动生成 OpenAPI Schema。

基础配置

# settings.py

INSTALLED_APPS = [
    "rest_framework",
    "drf_spectacular",
]

REST_FRAMEWORK = {
    "DEFAULT_SCHEMA_CLASS":
        "drf_spectacular.openapi.AutoSchema",
}

SPECTACULAR_SETTINGS = {
    "TITLE": "Example API",
    "DESCRIPTION": "REST API documentation",
    "VERSION": "1.0.0",
}

配置 API 文档路由

# urls.py

from django.urls import path
from drf_spectacular.views import (
    SpectacularAPIView,
    SpectacularSwaggerView,
    SpectacularRedocView,
)

urlpatterns = [
    path(
        "api/schema/",
        SpectacularAPIView.as_view(),
        name="schema",
    ),
    path(
        "api/docs/",
        SpectacularSwaggerView.as_view(
            url_name="schema"
        ),
        name="swagger-ui",
    ),
    path(
        "api/redoc/",
        SpectacularRedocView.as_view(
            url_name="schema"
        ),
        name="redoc",
    ),
]

这些路由分别用于:

  • /api/schema/:获取 OpenAPI Schema。
  • /api/docs/:查看 Swagger UI。
  • /api/redoc/:查看 ReDoc 文档。

extend_schema

@extend_schema 用于补充或覆盖自动生成的 OpenAPI 信息。

from drf_spectacular.utils import (
    extend_schema,
    OpenApiParameter,
    OpenApiTypes,
)
from rest_framework.views import APIView
from rest_framework.response import Response


class UserView(APIView):

    @extend_schema(
        tags=["Users"],
        summary="Get user",
        operation_id="getUser",
        parameters=[
            OpenApiParameter(
                name="user_id",
                type=OpenApiTypes.INT,
                location=OpenApiParameter.QUERY,
                required=True,
            )
        ],
        responses={200: UserSerializer},
    )
    def get(self, request):
        ...

参数、请求体与响应体

在 extend_schema 中:

参数对应 OpenAPI
parametersParameter Object
requestRequest Body Object
responsesResponses Object
operation_idoperationId
summarysummary
descriptiondescription
tagstags
deprecateddeprecated

例如:

@extend_schema(
    operation_id="createUser",
    request=UserCreateSerializer,
    responses={
        201: UserResponseSerializer,
        400: ErrorSerializer,
    },
)
def post(self, request):
    ...

extend_schema_view

对于需要在类级别为多个方法指定 Schema 的情况:

from drf_spectacular.utils import (
    extend_schema,
    extend_schema_view,
)


@extend_schema_view(
    get=extend_schema(
        operation_id="listUsers",
        responses=UserSerializer(many=True),
    ),
    post=extend_schema(
        operation_id="createUser",
        request=UserCreateSerializer,
        responses={201: UserSerializer},
    ),
)
class UserView(APIView):
    ...

extend_schema_view 适合统一描述一个 View 中的多个操作。

生成 OpenAPI 文件

python manage.py spectacular \
    --file schema.yaml \
    --validate

生成的 schema.yaml 可以用于:

  • Swagger UI
  • ReDoc
  • Orval
  • OpenAPI Generator
  • API Schema 校验

需要注意:Schema 校验成功只能说明文档基本符合规范,不能保证实际 API 的行为与文档完全一致。

17. OpenAPI 与前端代码生成

对于 React + TypeScript 项目,可以使用 Orval 根据 OpenAPI Schema 自动生成 API Client 和类型定义。

Django Serializer
       ↓
drf-spectacular
       ↓
OpenAPI Schema
       ↓
Orval
       ↓
TypeScript Types
Axios Functions
TanStack Query Hooks

例如后端:

@extend_schema(
    operation_id="getUser",
    responses=UserSerializer,
)

前端可能生成:

getUser();
useGetUser();

这种方式的主要价值是:

  • 减少前后端重复定义接口类型。
  • 提升请求和响应的类型安全性。
  • 简化 API Client 的维护。
  • 降低字段命名不一致的风险。

但需要注意:OpenAPI Schema 只是接口契约,生成的 TypeScript 类型并不能保证服务器运行时一定返回符合 Schema 的数据。

因此,后端的数据验证、测试和 Schema 的准确性仍然很重要。

18. OpenAPI 3.0 与 3.1 的区别

OpenAPI 3.1 对 Schema 的支持进行了重要调整,使其与 JSON Schema Draft 2020-12 更加一致。

特性OpenAPI 3.0OpenAPI 3.1
Schema 基础JSON Schema 扩展子集对齐 JSON Schema 2020-12
nullable使用 nullable: true通常使用联合类型表示 null
JSON Schema 关键字支持有限支持更完整
Schema 兼容性需要注意 OpenAPI 特有约束更接近标准 JSON Schema

OpenAPI 3.0:

type: string
nullable: true

OpenAPI 3.1:

type:
  - string
  - "null"

此外,在 OpenAPI 3.1 中,$ref 等相关机制也有进一步改进。

实际开发中,应根据使用的文档工具和代码生成器的兼容性选择 OpenAPI 版本,不一定需要立即升级到最新版本。

总结

OpenAPI 的核心内容可以分为四个部分:

分类重点
文档结构OpenAPI、Info、Servers、Paths
接口定义Operation、Parameters、RequestBody、Responses
数据模型Schema、Components、$ref、allOf、oneOf
工程实践SecuritySchemes、Swagger UI、drf-spectacular、Orval

最需要掌握的是:

  1. paths 和 Operation Object:描述接口。
  2. parameters 和 requestBody:描述输入。
  3. responses 和 schemas:描述输出及数据结构。
  4. components 和 $ref:实现组件复用。
  5. operationId:支持稳定的客户端代码生成。
  6. securitySchemes:描述接口认证要求。

对于 Django + DRF 开发,推荐以 Serializer 作为主要数据结构定义,再通过 drf-spectacular 自动生成 OpenAPI Schema,最后交给 Swagger UI 和 Orval 使用。


参考文档