JSON模式。生存还是毁灭?

建筑:使不必要的艺术成为现实。

弗雷德里克·凯斯勒

对于任何使用XML格式的SOAP协议的Web服务来说,一个可靠且经过时间考验的解决方案是XML Schema(xsd-scheme)的初步开发,它描述了XML消息的数据类型和结构,这对任何人来说都不是秘密。使用这种方法,开发人员具有明显的优势:他们对方案中设置的消息结构具有严格的标准化规则,规则的数量是有限的,并且他们使您可以自动验证XML格式的任何新消息。

但是,众所周知,由于XML语言的重载性(XML重载性)以及分布式系统REST(表示状态转移)软件开发的体系结构样式的传播,已被JSON(JavaScript对象标记)标记语言取代了XML语言。尽管REST样式本身不需要使用JSON(可以说根本不需要任何东西,但是“建议”),但是正如实践所示,开发REST API时,JSON通常用于描述消息正文。

因此,尽管使用XML Schema形式描述消息结构的经验大大简化了Web服务开发人员的工作,但是,使用JSON消息开发REST API的做法已牢固地进入了俄罗斯(不仅是我们自己)的IT界,在JSON消息的情况下被永久忽略。但是不是每个人都不能不高兴。

当熟悉XML Schema的开发人员每次需要通过文档解析重新发明轮子并重新发明验证逻辑时,形成了类似的JSON Schema草案。可在json-schema.org上获得,以及一些有关更改历史记录和使用示例的文件。尽管它以草稿状态发布,但长期以来,它一直受到所有流行的开发平台和不同语言的库的支持。JSON Schema

本身提供的消息结构功能少于XML Schema。如果有可能,通过XML Schema轻松描述的内容并非总是重复使用JSON Schema的琐碎任务。但是在这里,我认为这是一个优势。为什么? 众所周知,系统的算法越简单和线性化,它的可靠性就越高,文档的结构越简单,就越容易感知等。 我不禁引用:



“所有的创意都很简单,而所有简单的创意都是如此如果无法借助方案描述文档的复杂结构和可接受的选项集,那么在简化此文档的结构和逻辑的方向上是否值得研究?

前言


那么这篇文章是关于什么的呢?

我想更加注意描述JSON Schema传输的JSON消息的好处。尽管事实上“在入口处”,开发没有任何JSON方案的REST API总是更简单,更快捷,但是随着系统的发展,以某种方式缺少它会导致维护和支持系统的成本增加。此外,对消息结构的任何初步研究都有助于更好地组织消息交换,而不必在数据交换和处理消息的一般规则上进行不必要的重复。

另外,为了在俄语社区中传播有关JSON Schema的可能性及其使用规则的信息,我将与本文框架中的特定示例分享一些经验。

问题的提法


在开始研究JSON和JSON Schema之前,我将描述任务,我们将在下面考虑所有示例。

考虑组织中角色管理模型。我们假设我们需要通过调用REST服务以JSON格式将消息中现有角色模型的参考信息传递给相关系统,以消息的形式。

任务描述:

组织有员工,他们通常必须在多个系统中同时工作。同时,根据不同员工在组织中的角色,对一个或另一个系统组件(资源)的访问(权限)级别可能会有所不同,并且应该在系统中的用户授权期间进行控制。

例如,会计师(角色)将具有所有员工工资的薪资(资源)的读取和编辑访问权限(操作/凭据),而分析师(角色)仅具有读取访问权限(操作/凭据)根据其工资单(资源)。

有必要设计和描述组织中的角色管理模型。系统中的可用角色,一组可能的功能和资源必须根据要求转移到其他系统。


图1.角色模型的组成部分的

描述描述和实现角色模型的方法可以有所不同,但是无论实现如何,在这种情况下,最常见的是在角色模型中,我们可以区分以下基本组件:

  1. 角色(例如经理,会计师等)。
  2. 资源(例如文档,属性等)。
  3. 操作/权限(例如,读取,打印,创建等)。

在描述基于角色的访问时(作为可能的选项之一),他们诉诸于基于所选实体创建离散访问矩阵,例如:

表1.离散访问矩阵。
资源:文件资源:对象
角色:经理阅读,打印阅读,创建
角色:会计师阅读,创建

此外,该文章中,我们会先熟悉一下交换JSON数据文本格式的理论部分和使用JSON模式构造它们的规则,并作为例子,我会提供一个参考实体在JSON语言的角色,资源和操作及其JSON方案的描述中我们设定任务。

JavaScript对象符号(JSON)


JSON(英语JavaScript对象表示法)是基于JavaScript的基于文本的数据交换格式。

理论


JSON标记语言定义了一组有限的数据类型。对于“键”的一对“键”:值},始终使用字符串类型,对于“值”,适用的类型为:字符串,数字,对象(JSON类型),数组,布尔值(真或假)和null。


图2. JSON数据类型

该图显示了基本类型及其使用示例。我认为很简单。

JSON语法是JavaScript语法的子集,其中:

  1. 数据成对写入{{key“:value}。
  2. 数据用逗号分隔。
  3. 圆括号记录对象。
  4. 数组写在方括号中。
  5. “键”的名称区分大小写。


图3. JSON语法

实践


考虑一个将在服务中传输的角色目录的示例:


图4.以json格式描述的角色目录

从该示例可以看出,尽管基本类型数量很少,但如果组合使用,我们可以在必要时创建更复杂的消息结构。特别是在这里,我通过包含其他对象的数组的对象来描述角色的目录(在图4中用两个矩形突出显示)。

使用json-visualization工具以表格形式显示目录,如下所示:


图5. JSON格式的角色目录的可视化

相对而言,该目录代表3个“表”,用于在一组管理员,会计师和工人中分配角色。如有必要,可以扩展“属性”的组成。

在我看来,视觉表示简化了文本描述的感知。我们将为其他两个目录设置类似的结构。下面,我将仅给出一个用于权限(操作)和资源目录的表视图的示例。


图6. JSON格式的权限目录的


可视化图7. JSON格式的资源目录的可视化角色资源权限

目录的JSON文本格式的源消息可以从链接下载/查看
现在,让我们继续进行最有趣的事情:研究JSON Schema并为我们的参考书创建一个方案!

JSON模式


理论


由于JSON模式是以JSON格式编写的,因此它支持所有JSON类型以及附加类型:整数类型,它是数字类型的子类型。模式本身是JSON对象,旨在以JSON格式描述数据。以下是用于创建架构本身的数据类型的架构:


图8. JSON Schema数据类型

从图中可以看出,该架构使用与常规JSON文档相同的所有数据类型和语法原理,如图所示。图3.

现在,我们将考虑最重要的-方案中用于设置限制和构造JSON消息的规则。

JSON模式允许您:

  1. JSON.
  2. , — «keywords», .

一些“关键字”纯粹是描述性的,例如:“标题”,“描述”等,它们仅描述了该方案的目的。其他用于标识文档:“ $模式”。此关键字用于指示所需的模式版本。此关键字的值应该是代表URI的字符串,例如:“ $ schema”:“ json-schema.org/draft-04/schema# ”。

在此必须特别注意的是,电路工具并非支持所有版本。但是第4稿受到几乎所有人的支持。可以在json-schema.org/draft/2019-09/release-notes.html中找到不同版本的最新更改(JSON Schema 2019-09发行说明)

其余关键字直接用于验证JSON文档。我们现在将考虑它们。

表2. JSON Schema结构分析。关键字及其使用示例。
一种关键字范例/说明
用“关键字”描述方案"$schema"
"$schema": http://json-schema.org/draft-04/schema#

用于设置方案的草稿版本。
"$id"
"$id": "http://archi-blair.com/schemas/RolesDictionaryDef.json#"

用于指示文档或其子电路的唯一标识符。
"title"
"description"
"examples"
"comment"

{
"title": "JSON schema for dictionary",
"description": " ",
"examples": ["user", "manager"],
"comment": "     ))"
}

与项目数据类型无关的常规“验证关键字”"enum"
{"enum": [ "administrator", "superuser" ]}

进行检查以匹配至少1个值。
"const"
{"const": "user" }

检查是否完全符合设定值。
"type"
{"type": ["number", "string", "null", "boolean"]}
{"type": "array"}

指定架构将使用的数据类型。此关键字是可选的,关键字值可以是代表有效数据类型的字符串或代表有效数据类型的字符串数组。
Keywords, ,"type": "string"

minLength
maxLength
pattern
contentEncoding
contentMediaType

{
"type": "string",
"minLength": 3,
"maxLength": 10,
"pattern": "^test\\/[a-z-]+$",
"contentEncoding": "base64",
"contentMediaType": "application/json"
}

.
"type": "number" "type": "integer"

minimum
exclusiveMinimum
maximum
exclusiveMaximum
multipleOf

{
  "type": "number",
  "minimum": 1.5,
   "exclusiveMinimum": true,
   "maximum": 12.3,
   "exclusiveMaximum": true,
   "multipleOf": 0.5
}

.
"type": "object"

properties
required
dependencies
minProperties
maxProperties
propertyNames
patternProperties
additionalProperties


"employees": {
 "description": "",
 "type": "array",
  "uniqueItems": true,
   "items": {
     "type": "object",
     "properties": {
           "name": {
               "type": "string",
               "enum": ["employee"],
               "enumNames": [""]
	    },
            "enabled": {
                "type": "boolean",
                "default": true
             }
    },
 "additionalProperties": false
 }
}

, ( ).
"type": "array"

minItems
maxItems
uniqueItems
contains
items
additionalItems


"employees": {
 "description": "",
 "type": "array",
 "uniqueItems": true,
 "items": {
    "type": "object",
    "properties": {
          "name": {
               "type": "string",
               "enum": ["employee"],
               "enumNames": [""]
            },
          "enabled": {
                "type": "boolean",
                "default": true
            }
     },
 "additionalProperties": false
 }
}

, ( ).
"type": "boolean"

{"type": "boolean"}

boolean (true false).
"type": "null"

{"type": "null"}

null «» .
"type": "____"
"format": "____"

{
  "type": "string",
  "format": "date"
}

format . , .. -, , , .
"type": "____"
"default": "____"

{
"enabled": {
	"type": "boolean",
	"default": true
}	

.

, .
"not"
"if-then-else"

{
  "not": {
    "type": "string"
  }
}

, .
,"anyOf"
"oneOf"
"allOf"

{
  "type": "string",
  "anyOf": [
    {"const": "user"},
    {"const": "manager" }
  ]
}

, .
,"$id" "$ref"RolesDictionaryDef.json:

{
"$id": http://archi-blair.com/schemas/RolesDictionaryDef.json#
}

1 $ref ( ):


"items": {
"type": "object",
"minLength": 1,
"properties": {
  "name": {
  "description": "  ",
  "type": "string"
   },
"description": {
  "description": " ",
  "type": "string"
 },
"dictionaryGroup": {
  "$ref": "RolesDictionaryDef.json#/definitions/roles"
    }
},
"additionalProperties": false
}

2 JSON. , $ref .
"$ref" "definitions""$ref": "#/definitions/roles" , «definitions»:

{
"$schema": "http://json-schema.org/draft-04/schema#",
"description": " ",
"type": "object",
"properties": {
"dictionaries": {
   "description": "",
   "type": "array",
   "maxItems": 1,
   "items": {
      "type": "object",
      "minLength": 1,
      "properties": {
               "name": {
                  "description": " ",
                  "type": "string",
                  "enum": [
                     "Roles Dictionary"
                     ]
                 }
       "dictionaryGroups": {
             "$ref": "#/definitions/roles",
             "description": " "
          }
      },
 "additionalProperties": false
   }
  }
 },
 "additionalProperties": false,
     "definitions": {
          "roles": {
             "description": "",
             "type": "object",
             "properties": {
             "administrators": {
             "description": "",
             "type": "array",
             "uniqueItems": true,
             "items": {
             "type": "object",
             "properties": {
                   "name": {
                      "type": "string",
                      "enum": [
                         "administrator", 
                         "superuser"
                          ],
                        "enumNames": [
                          "", 
                          "-   "
                           ]
                         },
                    "enabled": {
                    "type": "boolean",
                    "default": true
                  }
              },
    "additionalProperties": false
      }
    }			
   },
  "additionalProperties": false
  }
 },
 "$id": "http://archi-blair.com/schemas/RolesDictionaryDef.json#"
}

, . $ref definitions.
"$ref"
.
"$ref": " #/definitions/roles"
"$ref": "RolesDictionaryDef.json#/definitions/roles"

, .
, .

我们检查了JSON模式关键字,该关键字使我们能够以JSON格式描述消息的未来结构。

在这里,您可以找到更多使用关键字的示例。

实践


在考虑完整的JSON方案的示例时,我们将类似于处理JSON格式的消息本身的示例。那些。对于角色,资源和权限(操作)目录的方案,我们将以树形和表格形式使用可视化表示形式,并结合方案的文字,我建议有兴趣的读者自己熟悉git

以下是角色参考图。


图9.角色目录的JSON模式示例

如图所示,该方案是一个JSON对象,描述了我们在JSON中传输角色目录的消息,如图4所示。在当前示例中,可以显示如何使用JSON方案描述了由对象组成的数组对象。

其他两个目录(权限和资源)的方案在结构上与角色目录的方案相同,因此,在此不做介绍,但在此给出将所有3个目录组合在一起的方案。

不幸的是,扩展过程中整个目录的方案无法显示在屏幕上,因此我们将考虑其中的一部分。


图10.包含角色,权限和资源的目录的JSON模式目录的示例

在该图中,我们看到目录数组中的某些对象是使用关键字“ anyOf”连接的。

同样,目录的表格表示可能会更直观。

考虑一下我们方案的另一个重要特征:


图11.在表视图中结合了角色,权限和资源目录的目录的JSON模式示例

从该图中我们看到,结合目录不会复制以前开发的角色,权限和资源目录中的代码,而是使用关键字“ $ ref ”

示例中考虑的目录位于同一目录中,但是,如果有必要,则不能遵守此规则,但是可以将其放在不同的目录中,以指示连接时它们的正确路径。此功能非常有用,因为它允许您重用以前创建的方案,仅将它们连接到所需的结构。

到此结束我对JSON和JSON Schema的回顾。我希望这里介绍的材料和讨论的示例将有助于探索JSON Schema的功能。

而不是结论


我认为是时候盘点了。那么,JSON Schema最终可以给我们带来什么?

  1. 它可以使开发人员的工作更加轻松,并可以改进用于验证JSON消息的代码。
    换句话说,它简化了软件支持和集成。
  2. 允许您开发服务,并为系统的未来开发制定带有“储备金”的数据格式和组成。
  3. 在面向文档,面向对象的数据库中应用文档验证。
  4. JSON-Schema可以帮助节省时间测试和记录API。
  5. 简化向后兼容性API支持。
  6. 允许您管理数据流。
  7. 使用在程序执行阶段获得的``枚举''中的值在运行时生成JSON Schema时进行灵活的验证。
    它可以用于状态机或状态为“枚举”的工作流程(来自特斯克VolCh
  8. JSON模式可以在执行施加DTO
    的(例如使用阿马克维奇

我们每个人在我们的IT项目中都决定“成为或不成为JSON模式”。上面,我列出了我认为使用电路的主要优点,并且出于其在项目中的应用已经值得考虑的考虑。

也许读者会希望帮助我继续这份名单?
我将不胜感激:)我

提供一些链接列表,这些链接对于使用JSON和JSON Schema非常有用

  1. .
  2. .
  3. ().
  4. ( ).
  5. - JSON-Schema.
  6. JSON Schema
  7. JSON Schema , ( alemiks), angular ngx-schema-form, AJSF ( anotherpit).

以及git仓库的链接,您可以在其中熟悉本文提供的源文件:包含示例源文件的仓库

系统架构师,
©Irina Blazhina

All Articles