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 Object | API 名称、版本、描述等元数据 | 是 |
| Paths Object | API 路径与 HTTP 操作 | 是 |
| Servers Object | API 服务器地址 | 否 |
| 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
| 字段 | 作用 |
|---|---|
| title | API 标题 |
| description | API 描述,支持 Markdown |
| version | API 版本 |
| 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 | 接口唯一标识 |
| parameters | Path、Query、Header、Cookie 参数 |
| requestBody | HTTP 请求体 |
| responses | HTTP 响应定义 |
| 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 | 参数位置 | 示例 |
|---|---|---|
| path | URL 路径 | /users/{userId} |
| query | 查询字符串 | ?page=2 |
| header | HTTP Header | X-Request-ID |
| cookie | Cookie | sessionid |
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 的区别
| 比较 | parameters | requestBody |
|---|---|---|
| 作用 | 描述独立请求参数 | 描述请求体 |
| 位置 | path/query/header/cookie | HTTP 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 | 认证机制定义 |
| links | API 操作间的关系 |
| 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
Session Cookie
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 |
|---|---|
parameters | Parameter Object |
request | Request Body Object |
responses | Responses Object |
operation_id | operationId |
summary | summary |
description | description |
tags | tags |
deprecated | deprecated |
例如:
@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.0 | OpenAPI 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 |
最需要掌握的是:
paths和 Operation Object:描述接口。parameters和requestBody:描述输入。responses和schemas:描述输出及数据结构。components和$ref:实现组件复用。operationId:支持稳定的客户端代码生成。securitySchemes:描述接口认证要求。
对于 Django + DRF 开发,推荐以 Serializer 作为主要数据结构定义,再通过 drf-spectacular 自动生成 OpenAPI Schema,最后交给 Swagger UI 和 Orval 使用。