kb.erickguedes.com
JSON: Formato e Manipulação

JSON Schema: Validação e Modelagem

Aula 2 de 4

Introdução ao JSON Schema

JSON Schema descreve a estrutura e validação de documentos JSON, similar ao XSD para XML.

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://exemplo.com/usuario.schema.json",
  "title": "Usuário",
  "description": "Schema para cadastro de usuários",
  "type": "object",
  "properties": {
    "nome": {
      "type": "string",
      "description": "Nome completo do usuário"
    },
    "email": {
      "type": "string",
      "format": "email"
    },
    "idade": {
      "type": "integer",
      "minimum": 18,
      "maximum": 120
    }
  },
  "required": ["nome", "email"]
}

Propriedades de Validação

Strings

{
  "type": "object",
  "properties": {
    "username": {
      "type": "string",
      "minLength": 3,
      "maxLength": 20,
      "pattern": "^[a-zA-Z0-9_]+$"
    },
    "email": {
      "type": "string",
      "format": "email"
    },
    "website": {
      "type": "string",
      "format": "uri"
    },
    "senha": {
      "type": "string",
      "minLength": 8,
      "pattern": "^(?=.*[A-Z])(?=.*[0-9])"
    }
  }
}

Números e Arrays

{
  "type": "object",
  "properties": {
    "idade": {
      "type": "integer",
      "minimum": 0,
      "exclusiveMaximum": 150
    },
    "altura": {
      "type": "number",
      "multipleOf": 0.01
    },
    "tags": {
      "type": "array",
      "items": { "type": "string" },
      "minItems": 1,
      "uniqueItems": true
    },
    "coordenadas": {
      "type": "array",
      "prefixItems": [
        { "type": "number" },
        { "type": "number" }
      ],
      "minItems": 2,
      "maxItems": 2
    }
  }
}

Enum e Conditional

{
  "type": "object",
  "properties": {
    "status": {
      "type": "string",
      "enum": ["ativo", "inativo", "pendente"]
    },
    "tipo": {
      "type": "string",
      "enum": ["pessoa_fisica", "pessoa_juridica"]
    },
    "documento": { "type": "string" }
  },
  "allOf": [
    {
      "if": { "properties": { "tipo": { "const": "pessoa_fisica" } } },
      "then": {
        "properties": {
          "documento": { "pattern": "^\\d{3}\\.\\d{3}\\.\\d{3}-\\d{2}$" }
        }
      }
    },
    {
      "if": { "properties": { "tipo": { "const": "pessoa_juridica" } } },
      "then": {
        "properties": {
          "documento": { "pattern": "^\\d{2}\\.\\d{3}\\.\\d{3}/\\d{4}-\\d{2}$" }
        }
      }
    }
  ]
}

allOf, oneOf, anyOf

{
  "type": "object",
  "properties": {
    "meioPagamento": {
      "oneOf": [
        {
          "type": "object",
          "properties": {
            "tipo": { "enum": ["cartao"] },
            "numero": { "type": "string", "pattern": "^\\d{16}$" },
            "cvv": { "type": "string", "pattern": "^\\d{3}$" }
          },
          "required": ["tipo", "numero", "cvv"]
        },
        {
          "type": "object",
          "properties": {
            "tipo": { "enum": ["boleto"] },
            "codigo_barras": { "type": "string", "pattern": "^\\d{44}$" }
          },
          "required": ["tipo", "codigo_barras"]
        }
      ]
    }
  }
}

Validação com Python

# Instalar validador
pip install jsonschema
import json
from jsonschema import validate, ValidationError

schema = {
    "$schema": "https://json-schema.org/draft/2020-12/schema",
    "type": "object",
    "properties": {
        "nome": {"type": "string", "minLength": 1},
        "email": {"type": "string", "format": "email"},
        "idade": {"type": "integer", "minimum": 18}
    },
    "required": ["nome", "email"]
}

# Documento válido
dados = {"nome": "João", "email": "[email protected]", "idade": 30}
try:
    validate(dados, schema)
    print("Documento válido!")
except ValidationError as e:
    print(f"Erro: {e.message}")

# Documento inválido
dados_invalidos = {"nome": "", "idade": 15}
try:
    validate(dados_invalidos, schema)
except ValidationError as e:
    print(f"Erro: {e.message}")

Lab: Criando e Validando Schemas

# 1. Schema de produto
cat << 'EOF' > produto.schema.json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://exemplo.com/produto.schema.json",
  "title": "Produto",
  "type": "object",
  "properties": {
    "sku": {
      "type": "string",
      "pattern": "^[A-Z]{3}-\\d{4}$"
    },
    "nome": {
      "type": "string",
      "minLength": 3,
      "maxLength": 100
    },
    "preco": {
      "type": "number",
      "minimum": 0.01,
      "exclusiveMaximum": 100000
    },
    "categorias": {
      "type": "array",
      "items": { "type": "string" },
      "minItems": 1,
      "uniqueItems": true
    },
    "estoque": {
      "type": "integer",
      "minimum": 0
    },
    "ativo": {
      "type": "boolean",
      "default": true
    }
  },
  "required": ["sku", "nome", "preco"]
}
EOF

# 2. Documentos para teste
cat << 'EOF' > produto-valido.json
{
  "sku": "ELE-0001",
  "nome": "Notebook Pro Max",
  "preco": 5499.99,
  "categorias": ["Eletrônicos", "Informática"],
  "estoque": 10,
  "ativo": true
}
EOF

cat << 'EOF' > produto-invalido.json
{
  "sku": "erro",
  "nome": "X",
  "preco": 0,
  "categorias": []
}
EOF

# 3. Validar com Python
python -c "
import json
from jsonschema import validate, ValidationError

with open('produto.schema.json') as f:
    schema = json.load(f)

for arquivo in ['produto-valido.json', 'produto-invalido.json']:
    with open(arquivo) as f:
        dados = json.load(f)
    try:
        validate(dados, schema)
        print(f'{arquivo}: VÁLIDO')
    except ValidationError as e:
        print(f'{arquivo}: INVÁLIDO - {e.message}')
"

JSON Schema é a linguagem de validação universal para APIs REST modernas — documentação, testes e validação em um único arquivo.