Skip to content

06 · 请求体 & 响应体 & Schema 复用:OpenAPI 的灵魂

生活类比requestBody = 你点单时填写的外卖订单纸条("汉堡 1 份、薯条 1 份、不要番茄、备注:少冰") responses = 厨房给你的出餐回执("打包好了,编号 042,5 分钟取餐") components.schemas = 大堂墙上贴的通用配料表(番茄酱、生菜、面包,所有汉堡都能引用)


1. 请求体 requestBody

注意:OpenAPI 3.0 把请求体从 parameters抽出来,单独作为 requestBody

yaml
paths:
  /users:
    post:
      summary: 创建用户
      requestBody:
        required: true                          # 是否必填
        description: 用户基本信息
        content:                                # 不同 MIME 类型
          application/json:
            schema:                             # 请求体的结构
              type: object
              properties:
                name: { type: string }
                email: { type: string, format: email }
              required: [name, email]
            example:                            # 单个示例
              name: Alice
              email: alice@example.com
      responses:
        '201': { description: Created }

1.1 多 MIME 类型同存

yaml
requestBody:
  content:
    application/json:                  # JSON
      schema: { $ref: '#/components/schemas/User' }
    application/xml:                   # XML
      schema: { $ref: '#/components/schemas/User' }
    multipart/form-data:               # 表单
      schema:
        type: object
        properties:
          name: { type: string }
          avatar: { type: string, format: binary }      # 文件

大多数 REST API 只用 application/json,但文件上传必须用 multipart/form-data

1.2 文件上传

yaml
paths:
  /upload:
    post:
      requestBody:
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                file:
                  type: string
                  format: binary       # ← 重点
                description:
                  type: string
              required: [file]
      responses:
        '200': { description: 上传成功 }

1.3 application/x-www-form-urlencoded(表单提交)

yaml
requestBody:
  content:
    application/x-www-form-urlencoded:
      schema:
        type: object
        properties:
          username: { type: string }
          password: { type: string, format: password }
        required: [username, password]

适合纯表单登录场景。前端用 URLSearchParams 发出,后端 @FormData 接。


2. 响应 responses

yaml
responses:
  '200':                              # 状态码(用字符串)
    description: 成功                  # 必填
    headers:                          # 响应头
      X-RateLimit-Remaining:
        schema: { type: integer }
        description: 剩余调用次数
    content:                          # 响应体
      application/json:
        schema:
          $ref: '#/components/schemas/User'
        examples:                     # 多组示例
          alice:
            value: { id: 1, name: Alice }
          bob:
            value: { id: 2, name: Bob }
  '404':
    description: 资源不存在
    content:
      application/json:
        schema:
          $ref: '#/components/schemas/Error'
  default:                            # 其他所有未声明的状态码
    description: 未预期的错误
    content:
      application/json:
        schema:
          $ref: '#/components/schemas/Error'

2.1 状态码必须是字符串

yaml
# ✗ 错(yaml 里 200 是数字)
responses:
  200:
    description: OK

# ✓ 对
responses:
  '200':
    description: OK

2.2 常见状态码 Cheat Sheet

含义用法
200OKGET / PUT / PATCH 成功
201CreatedPOST 创建成功
204No ContentDELETE 成功 / PUT 不返回内容
301Moved Permanently资源永久迁移
304Not Modified缓存未变(条件请求)
400Bad Request参数错误
401Unauthorized未登录 / token 无效
403Forbidden已登录但没权限
404Not Found资源不存在
409Conflict业务冲突(如重复创建)
422Unprocessable Entity参数格式对,但业务校验不通过
429Too Many Requests限流
500Internal Server Error后端崩了
502Bad Gateway网关下游挂了
503Service Unavailable维护中 / 过载
504Gateway Timeout网关超时

3. Schema 详解

schema 描述 "这个 JSON 长什么样"。语法是 JSON Schema 的子集(OpenAPI 3.1 完全兼容 2020-12 版)。

3.1 对象 schema

yaml
schema:
  type: object
  properties:
    id:
      type: integer
      readOnly: true            # 只读字段,POST 时不让传
    name:
      type: string
      minLength: 1
      maxLength: 50
    age:
      type: integer
      minimum: 0
      maximum: 150
    email:
      type: string
      format: email
    role:
      type: string
      enum: [admin, user, guest]
      default: user
    isActive:
      type: boolean
      default: true
    createdAt:
      type: string
      format: date-time
      readOnly: true
    password:
      type: string
      writeOnly: true           # 只写字段,响应时不返回
  required: [name, email]
  additionalProperties: false   # 不允许额外字段

3.2 数组 schema

yaml
schema:
  type: array
  items:                           # 每一项的 schema
    $ref: '#/components/schemas/User'
  minItems: 0
  maxItems: 100
  uniqueItems: true

3.3 嵌套对象

yaml
schema:
  type: object
  properties:
    user:
      type: object                  # 内嵌定义
      properties:
        name: { type: string }
    address:
      $ref: '#/components/schemas/Address'   # 引用
    orders:
      type: array
      items:
        $ref: '#/components/schemas/Order'

3.4 nullable(OpenAPI 3.0)

yaml
phone:
  type: string
  nullable: true              # 允许 null(OpenAPI 3.0 写法)

OpenAPI 3.1 改用 type 数组:

yaml
phone:
  type: [string, "null"]      # OpenAPI 3.1 写法

4. 复用 · components.schemas(最常用)

4.1 定义

yaml
components:
  schemas:
    User:
      type: object
      properties:
        id: { type: integer, readOnly: true }
        name: { type: string }
        email: { type: string, format: email }
        createdAt: { type: string, format: date-time, readOnly: true }
      required: [name, email]

    UserCreate:                     # 创建用的(不带 id 和 createdAt)
      type: object
      properties:
        name: { type: string }
        email: { type: string, format: email }
        password: { type: string, format: password, minLength: 6 }
      required: [name, email, password]

    UserUpdate:                     # 更新用的(所有字段可选)
      type: object
      properties:
        name: { type: string }
        email: { type: string, format: email }

    PageMeta:
      type: object
      properties:
        total: { type: integer }
        page: { type: integer }
        size: { type: integer }

    UserListResponse:
      type: object
      properties:
        items:
          type: array
          items: { $ref: '#/components/schemas/User' }
        meta:
          $ref: '#/components/schemas/PageMeta'

    Error:
      type: object
      properties:
        code: { type: integer }
        message: { type: string }
        details: { type: object }
      required: [code, message]

4.2 引用

yaml
paths:
  /users:
    get:
      responses:
        '200':
          content:
            application/json:
              schema: { $ref: '#/components/schemas/UserListResponse' }
    post:
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/UserCreate' }
      responses:
        '201':
          content:
            application/json:
              schema: { $ref: '#/components/schemas/User' }

4.3 命名约定(业内通用)

Schema 名用途
User完整对象(一般是响应)
UserCreate创建用(少了 id、时间戳)
UserUpdate更新用(字段都可选)
UserPatch局部更新
UserListResponse列表响应(含分页)
Error错误响应

5. 组合:allOf / oneOf / anyOf / not

5.1 allOf — 继承 / 合并

yaml
components:
  schemas:
    Pet:
      type: object
      properties:
        name: { type: string }
        age: { type: integer }
      required: [name]

    Dog:
      allOf:                          # 继承 Pet 的所有字段,再加自己的
        - $ref: '#/components/schemas/Pet'
        - type: object
          properties:
            breed: { type: string }
          required: [breed]

Dog 等价于:{ name, age, breed },必填 name + breed

5.2 oneOf — 必须满足其中恰好一个

yaml
PaymentMethod:
  oneOf:
    - $ref: '#/components/schemas/CreditCard'
    - $ref: '#/components/schemas/Alipay'
    - $ref: '#/components/schemas/WeChatPay'
  discriminator:                       # 用哪个字段区分
    propertyName: type
    mapping:
      credit_card: '#/components/schemas/CreditCard'
      alipay:      '#/components/schemas/Alipay'
      wechat:      '#/components/schemas/WeChatPay'

调用时,PaymentMethod 必须只能是其中之一(且 type 字段决定是哪个)。

5.3 anyOf — 满足至少一个(可以同时满足多个)

yaml
Search:
  anyOf:
    - type: object
      properties:
        keyword: { type: string }
    - type: object
      properties:
        author: { type: string }

请求体可以只有 keyword、只有 author、或者两个都有。

5.4 not

yaml
NonString:
  not:
    type: string         # 不能是字符串

oneOf / anyOf / not 在工程里用得不多,但 allOf 极其常用(继承 + 扩展)。


6. 实战 · 一份完整的"评论 API"

yaml
openapi: 3.0.3
info:
  title: 评论 API
  version: 1.0.0

paths:
  /comments:
    post:
      operationId: createComment
      summary: 发表评论
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/CommentCreate' }
            examples:
              short:
                value: { postId: 1, content: '👍' }
              normal:
                value: { postId: 1, content: '写得真好,学到了' }
      responses:
        '201':
          description: 评论成功
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Comment' }
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        default:
          $ref: '#/components/responses/Default'

  /comments/{id}:
    parameters:
      - name: id
        in: path
        required: true
        schema: { type: integer }
    get:
      operationId: getComment
      responses:
        '200':
          description: 评论详情
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Comment' }
        '404':
          $ref: '#/components/responses/NotFound'

components:
  schemas:
    Comment:                                  # 完整评论
      type: object
      properties:
        id: { type: integer, readOnly: true }
        postId: { type: integer }
        content: { type: string, minLength: 1, maxLength: 1000 }
        authorId: { type: integer, readOnly: true }
        createdAt: { type: string, format: date-time, readOnly: true }
        replyCount: { type: integer, readOnly: true, default: 0 }
      required: [id, postId, content, authorId, createdAt]

    CommentCreate:
      type: object
      properties:
        postId: { type: integer }
        content: { type: string, minLength: 1, maxLength: 1000 }
      required: [postId, content]

    Error:
      type: object
      properties:
        code: { type: integer }
        message: { type: string }
        traceId: { type: string }
      required: [code, message]

  responses:
    BadRequest:
      description: 参数错误
      content:
        application/json:
          schema: { $ref: '#/components/schemas/Error' }
          example: { code: 400, message: 'content 不能为空' }
    Unauthorized:
      description: 未登录
      content:
        application/json:
          schema: { $ref: '#/components/schemas/Error' }
    NotFound:
      description: 评论不存在
      content:
        application/json:
          schema: { $ref: '#/components/schemas/Error' }
    Default:
      description: 未知错误
      content:
        application/json:
          schema: { $ref: '#/components/schemas/Error' }

这种全 ref写法看起来啰嗦,但接口一多收益翻倍——加字段只需改 schemas 一个地方。


7. 常见坑

7.1 状态码必须用字符串

见 §2.1。

7.2 readOnly / writeOnly

yaml
User:
  type: object
  properties:
    id: { type: integer, readOnly: true }       # POST 不传,GET 才返
    password: { type: string, writeOnly: true }  # POST 必传,GET 不返

配合代码生成器,能自动从前端类型里把 readOnly 字段移除,不让前端误传。

7.3 example vs examples

yaml
# 单个示例
example:
  name: Alice

# 多个示例(更专业,UI 显示下拉选择)
examples:
  alice:
    summary: 普通用户
    value: { name: Alice }
  bob:
    summary: 管理员
    value: { name: Bob, role: admin }

注意:example 写在 schema 里也行,写在 content.application/json 下面也行;examples 只能写在 content 下面。

7.4 嵌套引用 $ref 不能跟其他字段并列

yaml
# ✗ 错
schema:
  $ref: '#/components/schemas/User'
  description: 用户对象           # 会被忽略!

# ✓ 对:用 allOf 包一层
schema:
  allOf:
    - $ref: '#/components/schemas/User'
  description: 用户对象

8. 章末面试题速览

  1. OpenAPI 3.0 为什么把 requestBody 单独抽出来? → 2.0 把请求体塞在 parameters 里很怪(不是真的"参数"),3.0 独立后能更清晰描述多 MIME 类型、复用 requestBody。
  2. allOfoneOf 的区别? → allOf = 全部都满足(合并 / 继承),oneOf = 恰好满足其中一个(多态)。
  3. readOnlywriteOnly 在生成代码时有什么用? → readOnly 字段不出现在创建 / 更新的 body 类型里;writeOnly 字段不出现在响应类型里。代码更安全。

🎬 可视化演示

下方 demo 是一个 "Schema 编辑器"——左边写字段,右边自动生成 yaml 和 JSON 示例。

→ 打开 06_request_body/demo.html

🎬 可视化演示

演示加载缓慢或样式异常?点此在新标签页打开 ↗