如果你是一名开发人员,那么你很可能经常使用JSON。但是,如何定义和验证JSON数据,以及如何避免因JSON数据格式错误而引发的问题呢?
本文将探讨什么是JSON模式,介绍一些JSON模式的示例,并说明谁来决定JSON模式的具体结构应该是什么样的。
先决条件
要理解这篇文章的内容,你需要了解一些JSON的基础知识,同时还需要对API的工作原理有基本的了解
。
目录
JSON究竟是什么?
JSON是一种常用的文档格式,通常用于通过API进行数据交换。它体积小、易于人类和机器阅读,而且许多编程语言都支持它。
但是,JSON对象并不具有固定的结构,可以用来表示不同类型的数据。因此,虽然JSON非常灵活,但它并不会强制规定数据必须遵循某种特定的结构或类型。这种灵活性也可能导致在数据交换过程中出现问题。
例如,如果服务器期望接收购物车中的商品信息,但却接收到包含支付交易数据的对象,那么服务器可能会无法正确解析这些数据,甚至可能因此崩溃。
另外,如果一个应用程序的服务器负责处理用户之间的消息传递,并且期望接收具有特定结构的数据,但客户端发送了格式不同的数据,那么在解析过程中就可能会出现问题,甚至可能导致安全漏洞。
正因为如此,才需要进行数据验证。
什么是验证?
在任何数据被发送之前对其进行验证,始终是一种良好的做法。验证就是将用户输入的数据与预期的结构及数据类型进行对比检查。
如果输入的数据格式、结构或数据类型与预期不符,那么该表单就会被拒绝,不会被发送到服务器。这样就可以避免服务器尝试解析错误类型的数据,从而防止潜在的安全问题发生。
JSON模式是一种用于描述其他JSON数据应具备的格式结构的文档。它实际上限制了服务器能够接收和处理的JSON数据的类型,确保只有正确类型的数据才能被服务器成功解析。
在Node.js中,像`package.json`这样的配置文件,甚至Azure的ARM模板,都是使用JSON格式编写的。这些文件必须经过验证,以确保其语法和结构是正确的,这样系统才能理解它们。验证工具的作用就是进行这种检查,从而帮助避免因解析错误而引发的各种问题。
JSON模式的结构
普通的JSON文件包含数据,而JSON模式则包含了关于这些数据的规则。这种模式是一种声明性的格式。
让我们来看一个包含数据的普通JSON文件的例子:
{
"username": "chidiadi",
"followers": 2200
}
现在,这个JSON模式定义了该数据的结构及约束规则:
{
"type": "object",
"properties": {
"username": {
"type": "string"
},
"followers": {
"type": "integer"
}
}
}
JSON模式本身也是由JSON对象构成的,但这些对象实际上代表了数据的约束条件及语法规范。
例如,这个模式要求有一个包含两个属性的JSON对象:`username`和`followers`。其中`username`属性必须是字符串类型(这是JSON支持的数据类型),而`followers`属性则必须是整数类型。整个父对象属于“object”类型。
这就是JSON模式的基本结构。根据实际需求,你可以在此基础上构建更复杂、更全面的模式。
如何创建JSON模式
要创建一个基本的JSON模式,你需要完成以下步骤:
-
使用`$schema`关键字来定义模式。
-
使用`$id`关键字为该模式指定一个唯一的标识符(URI)。
-
然后添加`title`和`description`关键字,这些是模式的注释信息。
-
最后定义`type`和`properties`等关键字,以规定数据的验证规则。
`$schema`关键字用于说明你的模式遵循的是哪个版本的JSON规范。例如:
{
"$schema": "https://json-schema.org/draft/2020-12/schema" }
`$id`关键字用于为模式指定一个唯一的URI,这样就可以在其他模式中引用它了。这种方式有助于重复使用和整理各种模式。例如:
{
"$id": "http://yourdomain.com/schemas/followers.json"
}
之后,就可以在另一个模式中使用`$ref`关键字来引用这个模式了。
{
"$ref": "http://yourdomain.com/schemas/followers.json"
}
`title`和`description`关键字属于注释信息,它们用于说明该模式的用途。例如:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "http://yourdomain.com/schemas/followers.json"
"title": "粉丝数量模式",
"description": "用于描述每个人的粉丝数量"
}
到目前为止,我们提到的所有关键字都不会影响验证的结果。这些关键字并没有说明预期的JSON文档应该是什么样的,也没有规定应该依据什么来进行验证。而`type`和`properties`这两个关键字恰恰起到了这样的作用——它们就是用于进行验证的关键字。
`type`关键字用于指定正在被该模式验证的对象的类型。这种类型可以是`string`、`object`、`array`、`number`、`boolean`或`null`。
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "http://yourdomain.com/schemas/followers.json",
"title": "Followers Schema",
"description": "Number of followers per person",
"type": "object"
}
如果你发送的JSON文件中包含一个作为父元素的数组,那么这个文件将会被拒绝。但是,这个对象应该包含哪些内容呢?这就是`properties`关键字发挥作用的地方了。
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "http://yourdomain.com/schemas/followers.json",
"title": "Followers Schema",
"description": "Number of followers per person",
"type": "object",
"properties": {
"username": {
"description": "The username of the user",
"type": "string"
},
"followers": {
"description": "The number of followers the user has",
"type": "integer"
}
}
}
在这里,我们添加了JSON文件中应该包含的键:`username`和`followers`。因此,那些包含其他键的文件将会无法通过验证。
以下这个JSON文件是符合要求的:
{
"username": "chidiadi",
"followers": 2200
}
而以下这个JSON文件则不符合要求:
{
"username": "chidiadi",
"name": "Chidiadi Anyanwu",
"followers": 2200,
}
它之所以会失败,是因为JSON文件中多出的`name`键并没有被包含在模式定义中。那些键中的`description`字段仅仅是一些注释,用于向开发者或查看模式文件的人说明这些键的含义而已。
还有一个`required`关键字,可以用来指定JSON文件中哪些键是必须存在的,否则文件就无法通过验证。例如,如果我们希望拒绝任何没有填写`username`字段的JSON文件,就可以将这个字段设置为必填项。
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "http://yourdomain.com/schemas/followers.json",
"title": "Followers Schema",
"description": "Number of followers per person",
"type": "object",
"properties": {
"username": {
"description": "The username of the user",
"type": "string"
},
"followers": {
"description": "The number of followers the user has",
"type": "integer"
}
},
"required": ["username"]
}
required关键字是一种用于对象验证的关键字,其值必须是一个数组。如果不使用这个关键字,那么该数组就相当于一个空数组。你可以在这个数组中添加多个键。例如,如果我们希望JSON文件中的用户名和粉丝数量都是必填字段,那么就可以将这两个字段都包含在数组中:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "http://yourdomain.com/schemas/followers.json",
"title": "粉丝信息规范",
"description": "每个人拥有的粉丝数量",
"type":"object",
"properties":{
"username": {
"description": "用户的用户名",
"type": "string"
},
"followers": {
"description": "用户拥有的粉丝数量",
"type": "integer"
}
},
"required":["username","followers"]
}
JSON规范的应用场景
OpenAPI
根据OpenAPI倡议的定义,
“OpenAPI规范为HTTP接口定义了一种与编程语言无关的标准接口描述方式,这种方式能够让人类和计算机在不需要访问源代码、额外文档或检查网络流量的情况下,了解某个服务的功能。”
简而言之,OpenAPI为开发人员提供了一种能够清晰地记录他们的API设计的方式,这样他们就可以方便地跟踪自己的开发进度。同时,对于那些需要使用这些API的人来说,这种规范也能帮助他们理解如何正确使用这些接口。
OAS是一种用于描述API的规范。它利用基于JSON格式的规范定义来说明请求和响应的结构。OpenAPI文档也可以用JSON或YAML格式编写。
{
"openapi": "3.2.0",
"info": {
"title": "计数器API",
"version": "1.0.0",
"description": "一个用于存储和增加计数值的简单API"
},
"servers": [
{
"url": "https://api.example.com"
}
],
"paths": {
"/counter": {
"get": {
"summary": "获取当前的计数器值",
"operationId": "getCounter",
"responses": {
"200": {
"description": "当前计数器值",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Counter"
}
}
}
}
}
},
"post": {
"summary": "增加计数器的数值",
"operationId": "incrementCounter",
"responses": {
"200": {
"description": "更新后的计数器值",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Counter"
}
}
}
}
}
}
}
},
"components": {
"schemas": {
"Counter": {
"type": "object",
"properties": {
"value": {
"type": "integer",
"example": 42
}
},
"required": ["value"]
}
}
}
}
对于 YAML 格式来说:
openapi: 3.2.0
info:
title: 计数器 API
version: 1.0.0
description: 这是一个用于存储和增加计数值的简单 API。
servers:
- url: https://api.example.com
paths:
/counter:
get:
summary: 获取当前的计数器值
operationId: getCounter
responses:
"200":
description: 当前的计数器值
content:
application/json:
schema:
$ref: "#/components/schemas/Counter"
post:
summary: 增加计数器的数值
operationId: incrementCounter
responses:
"200":
description: 更新后的计数器值
content:
application/json:
schema:
$ref: "#/components/schemas/Counter"
components:
schemas:
Counter:
type: object
properties:
value:
type: integer
example: 42
required:
- value
在这里,我们定义了一个名为 “Counter” 的模式对象。这个模式对象描述了 API 应该接收和发送的请求数据以及响应数据的结构。
该 API 支持两种 HTTP 方法:使用 POST 方法增加计数器的数值,使用 GET 方法获取当前的计数器值。其 URL 为 “https://api.example.com/counter”。
Azure 资源管理器模板
Azure 资源管理器负责在 Azure 账户中创建、删除和更新资源。Azure 门户、REST 客户端、Azure PowerShell 以及 Azure CLI 都依赖它来配置资源。您也可以使用 ARM 模板来定义基础设施的配置方案。
ARM 模板是一种 JSON 文件,它以声明性的方式描述了一个项目的基础设施配置信息。该模板指定了需要部署到特定租户、资源组、订阅或管理组中的资源类型。
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]"
}
},
"resources": [
{
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2025-06-01",
"name": "mystorageaccount",
"location": "[parameters('location')]",
"sku": {
"name": "Standard_LRS"
},
"kind": "StorageV2"
}
]
}
这个模板会创建一个名为 mystorageaccount 的存储账户,其位置取自相应的资源组。
如您所见,该模板中包含了一个 “schema” 关键字,这个关键字链接到了 Azure 团队制定的 JSON 模式文件,用于验证 ARM 模板的内容。因此,在部署模板之前,系统会先根据该模式文件对模板进行验证。
JSON模式项目
人们很容易将“JSON模式”这一概念与“JSON模式项目”混为一谈。但实际上,JSON模式是一个开源项目,它与互联网工程任务组(IETF)密切合作,其目标是统一构建JSON模式的规范。
关键在于,世界各地的所有开发人员在创建JSON模式时都可以使用相同的模板、格式和结构,这样一来,使用JSON的各类系统之间的互操作性就会得到提升。而这正是JSON作为一种文件交换格式所追求的目标。
如下图所示,Azure ARM模板模式就是基于JSON模式项目中某个版本的规范构建而成的:

如果您想了解更多关于JSON模式项目的信息,可以访问他们的官方网站。
结论
JSON模式在世界各地都被广泛使用,但人们对它的了解往往不够深入,也不常讨论它。实际上,模式是一种基础性技术,许多API以及OpenAPI、AsyncAPI、HL7 FHIR和SDFormat等项目都依赖于这种技术,因此作为开发者,了解JSON模式是非常有必要的。如果您喜欢这篇文章,请分享给更多人。您也可以通过LinkedIn或X与我联系。