熟悉 JSON Schema:给 JSON 数据制定规则

熟悉 JSON Schema:给 JSON 数据制定规则

JSON 是一种非常灵活的数据格式,正因为这种灵活性,同一份数据可以有很多种不同的表示方式。你可以用字符串表示数字,也可以用数字表示字符串;可以用数组包含不同类型的元素,也可以在对象中随意增减字段。


这种灵活性在某些场景下是优势,但在需要数据交换和验证的场景中却可能带来问题。JSON Schema 就是为了给 JSON 数据制定规则而设计的,它用 JSON 的语法来描述 JSON 数据应该遵循的结构和约束。

从 JSON 的灵活性说起


看一个简单的例子,下面这些都是合法的 JSON:

{"name": "张三", "age": 25}
{"name": "张三", "age": "25"}
{"username": "张三", "years": 25, "active": true}


从 JSON 格式的角度来说,这三个都没有问题。但如果你需要处理这些数据,就会发现麻烦了:age 字段有时是数字,有时是字符串;字段名也不统一;有些数据多了一些字段,有些又少了一些字段。


JSON Schema 可以定义一套规则,明确说明什么样的 JSON 数据是符合要求的。比如:

{
  "type": "object",
  "properties": {
    "name": {"type": "string"},
    "age": {"type": "integer"}
  },
  "required": ["name", "age"],
  "additionalProperties": false
}


这个 Schema 规定了:数据必须是对象类型,包含 name(字符串)和 age(整数)两个字段,不允许其他字段存在。

基本的类型约束


JSON Schema 最基础的功能是类型约束。JSON 支持的基本数据类型在 Schema 中都有对应的约束方式。


type 关键字用来指定数据类型:

{"type": "string"}     // 字符串
{"type": "number"}     // 数字(包含整数和小数)
{"type": "integer"}    // 整数
{"type": "boolean"}    // 布尔值
{"type": "array"}      // 数组
{"type": "object"}     // 对象
{"type": "null"}       // null 值


你也可以指定多个可能的类型:

{"type": ["string", "number"]}

这个规则允许数据是字符串或数字。


对于字符串类型,可以进一步限制内容特征:

{
  "type": "string",
  "minLength": 1,
  "maxLength": 100,
  "pattern": "^[a-zA-Z]+$"
}

这个规则要求字符串长度在 1-100 个字符之间,而且只能包含英文字母。


数字类型可以设置取值范围:

{
  "type": "number",
  "minimum": 0,
  "maximum": 100,
  "exclusiveMaximum": true
}

这个规则要求数字大于等于 0,小于 100(不包含 100)。

约束数组结构


数组是 JSON 中常用的数据结构,JSON Schema 提供了多种方式来约束数组。


最简单的是限制数组元素的类型和数量:

{
  "type": "array",
  "items": {"type": "string"},
  "minItems": 1,
  "maxItems": 5,
  "uniqueItems": true
}

这个规则要求数组包含 1-5 个字符串元素,而且每个元素都必须唯一。


如果数组中不同位置的元素有不同的约束,可以用数组形式的 items

{
  "type": "array",
  "items": [
    {"type": "string"},
    {"type": "number"},
    {"type": "boolean"}
  ],
  "minItems": 3,
  "maxItems": 3
}

这个规则要求数组恰好包含 3 个元素:第一个是字符串,第二个是数字,第三个是布尔值。

约束对象结构


对象是 JSON 中最复杂的数据类型,JSON Schema 提供了丰富的约束选项。


properties 用来定义对象的属性:

{
  "type": "object",
  "properties": {
    "id": {"type": "integer"},
    "name": {"type": "string"},
    "active": {"type": "boolean"}
  }
}


required 指定哪些属性是必需的:

{
  "type": "object",
  "properties": {
    "id": {"type": "integer"},
    "name": {"type": "string"},
    "email": {"type": "string"}
  },
  "required": ["id", "name"]
}

这个规则要求 id 和 name 必须存在,email 是可选的。


additionalProperties 控制是否允许未定义的属性:

{
  "type": "object",
  "properties": {
    "name": {"type": "string"}
  },
  "additionalProperties": false
}

设置为 false 后,对象只能包含 properties 中定义的属性。如果你想允许额外属性但要约束它们的类型,可以这样写:

{
  "type": "object",
  "properties": {
    "name": {"type": "string"}
  },
  "additionalProperties": {"type": "string"}
}

这样,除了 name 字段外,其他字段必须都是字符串类型。

更精确的值约束


除了类型约束,JSON Schema 还支持更精确的值约束。


enum 限制字段只能取特定的值:

{
  "type": "string",
  "enum": ["pending", "processing", "completed", "cancelled"]
}


const 要求字段必须是特定的值:

{"const": "success"}


对于字符串,format 提供了常用格式的验证:

{"type": "string", "format": "email"}
{"type": "string", "format": "uri"}
{"type": "string", "format": "date"}
{"type": "string", "format": "date-time"}
{"type": "string", "format": "ipv4"}


组合约束条件


有时候需要更复杂的约束逻辑,JSON Schema 提供了逻辑组合关键字。


anyOf 表示满足其中任意一个条件:

{
  "anyOf": [
    {"type": "string", "maxLength": 5},
    {"type": "number", "minimum": 0}
  ]
}


allOf 表示必须同时满足所有条件:

{
  "allOf": [
    {"type": "string"},
    {"minLength": 2},
    {"maxLength": 10}
  ]
}


oneOf 表示只能满足其中一个条件:

{
  "oneOf": [
    {"type": "number", "multipleOf": 5},
    {"type": "number", "multipleOf": 3}
  ]
}


not 表示不能满足指定条件:

{
  "type": "string",
  "not": {"enum": ["admin", "root"]}
}


引用和模块化


当 Schema 变得复杂时,可以使用引用来避免重复定义。

{
  "$defs": {
    "person": {
      "type": "object",
      "properties": {
        "name": {"type": "string"},
        "age": {"type": "integer"}
      },
      "required": ["name"]
    }
  },
  "type": "object",
  "properties": {
    "author": {"$ref": "#/$defs/person"},
    "reviewer": {"$ref": "#/$defs/person"}
  }
}

这样,person 的定义可以在多个地方重复使用。


你也可以引用外部文件中的 Schema:

{"$ref": "https://example.com/schemas/person.json"}


条件约束


JSON Schema 还支持条件约束,根据某些字段的值来决定其他字段的约束规则:

{
  "type": "object",
  "properties": {
    "type": {"enum": ["personal", "business"]},
    "name": {"type": "string"},
    "company": {"type": "string"},
    "taxId": {"type": "string"}
  },
  "if": {
    "properties": {"type": {"const": "business"}}
  },
  "then": {
    "required": ["company", "taxId"]
  },
  "else": {
    "not": {
      "anyOf": [
        {"required": ["company"]},
        {"required": ["taxId"]}
      ]
    }
  }
}

这个规则表示:如果 type 是 "business",那么 company 和 taxId 是必需的;否则这两个字段不应该存在。

在 Apifox 中应用 JSON Schema


了解了 JSON Schema 的基本语法后,你会发现在 Apifox 中使用它非常直观。

Apifox 原生支持 JSON Schema,你可以直接在接口定义中使用完整的 Schema 语法。


当你创建接口时,可以在请求体或响应体的 Schema 编辑器中直接编写 JSON Schema 代码。比如定义一个用户数据的结构:

{
  "type": "object",
  "properties": {
    "id": {
      "type": "integer",
      "minimum": 1,
      "description": "用户唯一标识"
    },
    "username": {
      "type": "string",
      "minLength": 3,
      "maxLength": 20,
      "pattern": "^[a-zA-Z0-9_]+$",
      "description": "用户名"
    },
    "email": {
      "type": "string",
      "format": "email",
      "description": "邮箱地址"
    },
    "status": {
      "type": "string",
      "enum": ["active", "inactive", "suspended"],
      "description": "账户状态"
    },
    "profile": {
      "type": "object",
      "properties": {
        "firstName": {"type": "string"},
        "lastName": {"type": "string"},
        "birthDate": {"type": "string", "format": "date"},
        "avatar": {"type": "string", "format": "uri"}
      },
      "additionalProperties": false
    },
    "tags": {
      "type": "array",
      "items": {"type": "string"},
      "uniqueItems": true,
      "maxItems": 10
    }
  },
  "required": ["id", "username", "email", "status"],
  "additionalProperties": false
}

Apifox 会根据这个 Schema 自动生成清晰的文档界面,显示每个字段的类型、约束条件和说明。同时,它还能根据 Schema 生成符合规则的 Mock 数据用于测试。

apifox json schema


数据模型的复用


Apifox 的数据模型功能让 JSON Schema 的复用变得更简单。你可以创建通用的数据模型,然后在多个接口中引用:

{
  "User": {
    "type": "object",
    "properties": {
      "id": {"type": "integer"},
      "username": {"type": "string"},
      "email": {"type": "string", "format": "email"}
    },
    "required": ["id", "username", "email"]
  },
  "ApiResponse": {
    "type": "object",
    "properties": {
      "code": {"type": "integer"},
      "message": {"type": "string"},
      "data": {}
    },
    "required": ["code", "message"]
  }
}


然后在具体接口中可以这样使用:

{
  "allOf": [
    {"$ref": "#/components/schemas/ApiResponse"},
    {
      "properties": {
        "data": {"$ref": "#/components/schemas/User"}
      }
    }
  ]
}

这样就创建了一个包含用户数据的标准 API 响应格式。

自动化验证和测试


基于 JSON Schema 的定义,Apifox 可以自动验证接口的请求和响应数据是否符合规范。当你发送测试请求时,如果返回的数据不符合 Schema 定义,Apifox 会明确指出哪些字段不符合要求。


这种自动化验证可以帮你及时发现数据格式的问题,避免因为数据结构不一致而导致的 Bug。特别是在接口较多的项目中,手动检查每个接口的数据格式是不现实的,JSON Schema 的自动验证就显得特别有价值。


JSON Schema 本质上是一套描述 JSON 数据结构的规则语言。掌握了它的语法和特性,你就能精确地定义数据应该有什么样的结构和约束,让数据的生产者和消费者都能按照统一的标准来处理数据。

订阅
qrcode

订阅

随时随地获取 Apifox 最新动态