Esquema JSON. Ser ou não ser?

Arquitetura: a arte de tornar desnecessariamente necessário.

Frederick Kiesler

Não é segredo para ninguém que, para qualquer serviço da Web que usa o protocolo SOAP com mensagens XML, uma solução confiável e testada pelo tempo é o desenvolvimento preliminar do Esquema XML ( esquema xsd) que descreve os tipos de dados e a estrutura das mensagens XML. Com essa abordagem, os desenvolvedores têm uma vantagem clara: possuem regras padronizadas estritas para a estrutura das mensagens definidas no esquema, o número de regras é finito e permitem automatizar a verificação de qualquer nova mensagem no formato XML.

Mas também é sabido que a linguagem XML foi substituída pela linguagem de marcação JSON (JavaScript Object Notation) devido ao seu maior peso (peso XML), bem como à disseminação do estilo arquitetônico do desenvolvimento de software REST (REpresentational State Transfer) para sistemas distribuídos. Embora o próprio estilo REST não exija o uso de JSON (pode-se dizer que não exige nada, mas “recomenda”), mas, como mostra a prática, com mais frequência ao desenvolver uma API REST, o JSON é usado para descrever o corpo das mensagens.

Portanto, a prática de desenvolver uma API REST com mensagens JSON entrou firmemente na vida da TI na Rússia (e não apenas na nossa), embora a experiência em descrever a estrutura de mensagens na forma de XML Schema tenha simplificado bastante a vida dos desenvolvedores de serviços da Web ao mesmo tempo, persistentemente ignorado no caso de mensagens JSON. Mas nem todo mundo que não pode deixar de se alegrar.

Quando os desenvolvedores familiarizados com o XML Schema enfrentaram a necessidade de reinventar a roda toda vez que analisam documentos e reinventam a lógica de validação, um rascunho semelhante ao JSON Schema foi formado . Está disponível em json-schema.org, bem como vários documentos sobre o histórico de alterações e exemplos de uso. E, apesar de publicado em status de rascunho, há muito tempo é suportado por todas as plataformas e bibliotecas de desenvolvimento populares em diferentes idiomas. O

próprio esquema JSON fornece menos estrutura de mensagens que o esquema XML . O que pode ser facilmente descrito através do Esquema XML nem sempre será uma tarefa trivial para repetir usando o Esquema JSON, se possível. Mas aqui eu consideraria esse fato uma vantagem. Por quê?

Sabe-se que quanto mais simples e linear o algoritmo do sistema, mais confiável é, mais simples é a estrutura do documento, mais fácil é a percepção etc.

Eu não posso ajudar, mas citação:"Tudo engenhoso é simples, e tudo simples é engenhoso . " E se não for possível descrever a estrutura complexa do documento e o conjunto de opções aceitáveis ​​usando o esquema, talvez valha a pena procurar na direção de simplificar a estrutura e a lógica da formação deste documento?

Prefácio


Então, sobre o que é este artigo?

Gostaria de chamar mais atenção para os benefícios da descrição de mensagens JSON transmitidas pelo esquema JSON. Apesar do fato de que "na entrada", o desenvolvimento de uma API REST sem nenhum esquema JSON é sempre mais simples e rápido, mas com o crescimento do sistema, sua ausência de uma maneira ou de outra leva a um aumento no custo de manutenção e suporte do sistema. Além disso, qualquer estudo preliminar da estrutura de mensagens contribui para uma melhor organização da troca de mensagens, sem duplicação desnecessária na troca de dados e nas regras gerais para o processamento.

Além disso, para disseminar informações na comunidade de língua russa sobre as possibilidades do esquema JSON e as regras para trabalhar com ele, compartilharei minha experiência com exemplos específicos na estrutura deste artigo.

Formulação do problema


Antes de começar a estudar o JSON e o JSON Schema, descreverei a tarefa na qual consideraremos todos os exemplos abaixo.

Considere um modelo de gerenciamento de função em uma organização. Assumimos que precisaremos transferir informações de referência no modelo de função existente para sistemas dependentes em mensagens no formato JSON chamando um serviço REST.

Descrição da tarefa:

A organização possui funcionários, eles geralmente precisam trabalhar simultaneamente em vários sistemas. Além disso, o nível de acesso (autoridade) a vários componentes do sistema (recursos) para diferentes funcionários, dependendo de sua função na organização, pode ser diferente e deve ser controlado durante a autorização do usuário no sistema.

Por exemplo, um contador (função) terá acesso de leitura e edição (operações / credenciais) às folhas de pagamento (recurso) dos salários de todos os funcionários, e um analista (função), por exemplo, terá somente acesso de leitura (operação / credenciais) de acordo com seu recibo de pagamento (recurso).

É necessário projetar e descrever um modelo de gerenciamento de função em uma organização. Funções disponíveis, um conjunto de possíveis poderes e recursos no sistema deve ser transferido para outros sistemas, mediante solicitação.


Figura 1. Apresentação dos componentes do modelo: Os

métodos para descrever e implementar o modelo podem diferir, mas, independentemente da implementação, na maioria das vezes no modelo, podemos distinguir os seguintes componentes básicos:

  1. Função (por exemplo, gerente, contador, etc.).
  2. Recurso (por exemplo, documento, propriedade etc.).
  3. Operação / autoridade (por exemplo, ler, imprimir, criar etc.).

Ao descrever o acesso baseado em função (como uma das opções possíveis), eles recorrem à criação de uma matriz de acesso discreta com base nas entidades selecionadas, por exemplo:

Tabela 1. Matriz de acesso discreto.
Recurso: documentosRecurso: objetos
Função: gerenteler, imprimirleia, crie
Função: contadorleia, crieler

Além disso, neste artigo, nos familiarizaremos primeiro com o componente teórico do formato de texto para troca de dados JSON e as regras para estruturá-los usando o esquema JSON. Como exemplos, descreverei as entidades das entidades para as funções, recursos e operações na linguagem JSON e seus esquemas JSON dentro de nosso definir tarefa.

Notação de Objeto JavaScript (JSON)


JSON (inglês JavaScript Object Notation) é um formato de troca de dados baseado em texto baseado em JavaScript.

Teoria


A linguagem de marcação JSON define um conjunto limitado de tipos de dados. Para o par {"chave": valor} para a "chave" sempre use o tipo string, para o "valor" os tipos são aplicáveis: string, número, objeto (tipo JSON), matriz, booleano (verdadeiro ou falso) e nulo.


Figura 2. Tipos de dados JSON

A figura mostra os tipos básicos e exemplos de uso. Simples o suficiente, na minha opinião.

A sintaxe JSON é um subconjunto da sintaxe JavaScript, em que:

  1. Os dados são gravados como pares {"chave": valor}.
  2. Os dados são separados por vírgulas.
  3. Parênteses curvos registram objetos.
  4. As matrizes são escritas entre colchetes.
  5. Os nomes das "chaves" diferenciam maiúsculas de minúsculas.


Figura 3. Sintaxe JSON

Prática


Considere um exemplo de um diretório de funções que transferiremos no serviço:


Figura 4. Descrição de um diretório de funções no formato json

No exemplo, pode-se observar que, apesar de um número tão pequeno de tipos básicos, quando combinados, podemos criar estruturas de mensagens mais complexas, se necessário. Aqui, em particular, descrevo o diretório de funções através de um objeto de matrizes contendo outros objetos (na figura 4 são destacados por dois retângulos).

Em um formulário tabular usando as ferramentas json-visualization, o diretório pode ser representado da seguinte maneira:


Figura 5. Visualização do diretório de funções no formato JSON

O diretório, relativamente falando, representa 3 "tabelas" para atribuir funções em um grupo de administradores, contadores e trabalhadores. A composição dos "atributos" pode ser expandida, se necessário.

A representação visual, na minha opinião, simplifica a percepção da descrição do texto. Vamos definir uma estrutura semelhante para os outros dois diretórios. Vou dar abaixo um exemplo de apenas uma exibição de tabela para um diretório de autoridade (operações) e recursos.


Figura 6. Visualizações do diretório de permissões no formato JSON


Figura 7. Visualizações do diretório de recursos no formato JSON As

mensagens de origem no formato de texto JSON para o diretório de funções , recursos e permissões podem ser baixadas / exibidas no link .
Agora vamos para o mais interessante: estudar o JSON Schema e criar um esquema para nossos livros de referência!

Esquema JSON


Teoria


Como o esquema json é gravado no formato JSON, ele suporta todos os tipos JSON mais a adição: o tipo inteiro, que é um subtipo do tipo numérico. O esquema em si é um objeto JSON e destina-se a descrever dados no formato JSON. A seguir, é apresentado um esquema dos tipos de dados usados ​​para criar o próprio esquema:


Figura 8. Tipos de dados do esquema JSON

Como você pode ver na figura, o esquema usa todos os mesmos tipos de dados, bem como os mesmos princípios de sintaxe de um documento JSON comum, mostrado em figura 3.

Agora, consideraremos as mais importantes - as regras usadas no esquema para definir restrições e estruturar as mensagens JSON.

O esquema JSON permite:

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

Algumas "palavras-chave" são puramente descritivas, como: "título", "descrição" etc., que simplesmente descrevem o objetivo do esquema. Outros são usados ​​para identificar o documento: "$ schema". Essa palavra-chave é usada para indicar a versão desejada do esquema. O valor dessa palavra-chave deve ser uma sequência que represente um URI, por exemplo: "$ schema": " json-schema.org/draft-04/schema# ".

É muito importante observar aqui que nem todas as versões podem ser suportadas pela sua ferramenta de circuito. Mas o quarto rascunho é apoiado por quase todos. As alterações mais recentes (Notas da versão do esquema JSON 2019-09) para versões diferentes podem ser encontradas em json-schema.org/draft/2019-09/release-notes.html .

As palavras-chave restantes são usadas diretamente para validar o documento JSON. Agora vamos considerá-los.

Tabela 2. Análise da estrutura do esquema JSON. Palavras-chave e seus exemplos de uso.
Um tipoPalavras-chave)Exemplo / Descrição
"Palavras-chave" para descrever o esquema"$schema"
"$schema": http://json-schema.org/draft-04/schema#

Usado para definir a versão de rascunho do esquema.
"$id"
"$id": "http://archi-blair.com/schemas/RolesDictionaryDef.json#"

Usado para indicar um identificador exclusivo para um documento ou seus subcircuitos.
"title"
"description"
"examples"
"comment"

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

Geral "Palavras-chave de validação", independentemente do tipo de dados do item"enum"
{"enum": [ "administrator", "superuser" ]}

É feita uma verificação para corresponder a pelo menos 1 valor.
"const"
{"const": "user" }

É feita uma verificação para a conformidade exata com o valor definido.
"type"
{"type": ["number", "string", "null", "boolean"]}
{"type": "array"}

Especifica o tipo de dados que o esquema usará. Essa palavra-chave é opcional e o valor da palavra-chave pode ser uma sequência que representa um tipo de dados válido ou uma matriz de sequências representando tipos de dados válidos.
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"

, .
, .

Examinamos as palavras-chave do esquema JSON, que nos permitem descrever a estrutura futura de nossas mensagens no formato JSON.

Aqui você pode encontrar mais exemplos de uso de palavras-chave.

Prática


Ao considerar exemplos de esquemas JSON concluídos, procederemos de maneira semelhante aos exemplos de trabalho com as próprias mensagens no formato JSON. Essa. usaremos a representação visual em forma de árvore e tabular para nossos esquemas de diretórios de funções, recursos e autoridades (operações) e com o texto dos esquemas que proponho ler os leitores interessados ​​por conta própria no git .

A seguir, é apresentado um diagrama para uma referência de função.


Figura 9. Exemplo de esquema JSON para o diretório de funções

Como podemos ver na figura, o esquema é um objeto JSON e descreve nossa mensagem para transmitir o diretório de funções em JSON, que foi mostrado na Figura 4. No exemplo atual, pode ser mostrado como usar o esquema JSON Um objeto de matriz que consiste em objetos é descrito.

Os esquemas dos outros dois diretórios (autoridade e recursos) são idênticos em estrutura ao esquema do diretório de funções, portanto não os darei aqui, mas darei um esquema que combine todos os três diretórios.

Infelizmente, o esquema de todo o diretório durante a expansão não se encaixa na tela; portanto, consideraremos parte dele.


Figura 10. Um exemplo de diretório JSON Schema que combina um diretório de funções, permissões e recursos.Na

figura, vemos que alguns dos objetos na matriz de diretórios são conectados usando a palavra-chave "anyOf".

Além disso, talvez, uma representação tabular do diretório seja mais visual.

Considere outra característica importante do nosso esquema:


Figura 11. Um exemplo JSON Schema de um diretório combinando um repertório de papéis, permissões e recursos em uma exibição de tabela

A partir da figura, vemos que um diretório combinando faz código não duplicado diretórios previamente desenvolvidos de papéis, permissões e recursos, mas usa a palavra-chave "$ ref "

Os diretórios considerados nos exemplos estão no mesmo diretório, mas, se necessário, essa regra não pode ser observada, mas pode ser colocada em diretórios diferentes, indicando o caminho correto para eles durante a conexão. Esse recurso é muito útil, pois permite reutilizar esquemas criados anteriormente, conectando-os apenas à estrutura desejada.

Isso conclui minha análise do esquema JSON e JSON. Espero que o material apresentado aqui e os exemplos discutidos sejam úteis para explorar os recursos do JSON Schema.

Em vez de uma conclusão


Eu acho que é hora de fazer um balanço. Então, o que o JSON Schema pode nos dar?

  1. Isso pode facilitar a vida dos desenvolvedores e melhorar o código para validar mensagens JSON.
    Em outras palavras, simplifica o suporte e a integração de software.
  2. Permite desenvolver serviços, elaborando os formatos e a composição dos dados com uma "reserva" para o desenvolvimento futuro do sistema.
  3. Aplique a verificação de documentos em bancos de dados orientados a documentos e orientados a objetos.
  4. O JSON-Schema pode ajudar a economizar tempo testando e documentando a API.
  5. Simplifique o suporte à API de compatibilidade com versões anteriores.
  6. Permite gerenciar fluxos de dados.
  7. Validação flexível ao gerar o esquema JSON em tempo de execução com valores em "enum" obtidos no estágio de execução do programa.
    Pode ser usado para uma máquina de estado ou fluxo de trabalho com status em “enum” (exemplo de aplicação deTsdk e VolCh)
  8. O esquema JSON pode ser aplicado na implementação do DTO
    (exemplo de uso deamarkevich)

Cada um de nós decide "Ser ou não ser JSON Schema" em nossos projetos de TI. Acima, dei uma lista do que considero ser a principal vantagem do uso de circuitos e pelo que já vale a pena pensar em sua aplicação em projetos.

Talvez os leitores queiram me ajudar a continuar esta lista?
Serei grato :)

Também darei uma lista de links, na minha opinião, úteis para trabalhar com o JSON e o JSON Schema

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

E um link para o repositório git, onde você pode se familiarizar com os arquivos de origem fornecidos para revisão neste artigo: um repositório com os arquivos de origem dos exemplos .

Arquiteto de sistemas,
© Irina Blazhina

All Articles