Esquemas JSON (Schemas)

📚 Índice

Introdução

Schemas JSON permitem definir a estrutura, tipo de dados e regras de validação para seus documentos. O Document Hub suporta JSON Schema Draft 4 e superior.

Escopo Necessário

Para gerenciar schemas, você precisa de um token com o escopo schema:manage.

O que são JSON Schemas

JSON Schema é um padrão para descrever e validar a estrutura de dados JSON. Ele define:

  • Tipos de dados permitidos (string, number, object, array, etc.)
  • Campos obrigatórios (required)
  • Restrições (min/max, pattern, enum, etc.)
  • Estrutura aninhada (propriedades dentro de objetos)
  • Validações personalizadas

Exemplo Simples

{
  "type": "object",
  "required": ["name", "email"],
  "properties": {
    "name": {
      "type": "string",
      "minLength": 2
    },
    "email": {
      "type": "string",
      "format": "email"
    },
    "age": {
      "type": "integer",
      "minimum": 0,
      "maximum": 150
    }
  }
}

Este schema valida que:

  • O documento deve ser um objeto
  • Campos name e email são obrigatórios
  • name deve ser string com pelo menos 2 caracteres
  • email deve ser string em formato de email válido
  • age (opcional) deve ser inteiro entre 0 e 150

Por que Usar Schemas

Benefícios

  1. Consistência de Dados

    • Garante que todos os documentos sigam o mesmo formato
    • Evita dados malformados ou incompletos
  2. Validação Automática

    • Rejeita documentos inválidos antes de salvá-los
    • Retorna erros descritivos para correção
  3. Documentação Viva

    • O schema serve como documentação da estrutura esperada
    • Outros desenvolvedores entendem o formato rapidamente
  4. Segurança

    • Previne injeção de campos não esperados
    • Valida tipos de dados para evitar problemas de segurança
  5. Evolução Controlada

    • Permite evolução do formato de dados de forma controlada
    • Facilita migrações

JSON Schema no Document Hub

Estrutura do Schema

Schemas são associados a um escopo específico:

Cliente → Ambiente → Contexto → Tipo

Isso significa que você pode ter schemas diferentes para:

  • O mesmo tipo em ambientes diferentes
  • O mesmo tipo em contextos diferentes

Modelo de Dados

{
  "id": 1,
  "client_id": "9fc42fe9-a4fd-443c-8d49-b85ece2151b9",
  "environment": "production",
  "context": "orders",
  "type": "invoice",
  "schema": {
    /* JSON Schema aqui */
  },
  "created_at": "2024-01-15T10:30:00.000000Z",
  "updated_at": "2024-01-15T10:30:00.000000Z"
}

Criar/Atualizar Schemas

Endpoint

POST /api/v1/client/{client}/{environment}/context/{context}/type/{type}/schema

Nota: Este endpoint funciona como upsert:

  • Se o schema não existe, ele é criado (retorna 201)
  • Se o schema existe, ele é atualizado (retorna 200)

Headers Necessários

Authorization: Bearer {SEU_TOKEN}
Content-Type: application/json

Body da Requisição

{
  "schema": {
    /* Seu JSON Schema aqui */
  }
}

Exemplo 1: Schema Simples para Faturas

curl -X POST "https://document-hub-api-xp.wake.tech/api/v1/client/9fc42fe9-a4fd-443c-8d49-b85ece2151b9/production/context/orders/type/invoice/schema" \
  -H "Authorization: Bearer {SEU_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "schema": {
      "type": "object",
      "required": ["customer_id", "amount", "currency", "status"],
      "properties": {
        "customer_id": {
          "type": "string",
          "pattern": "^CUST-[0-9]+$"
        },
        "invoice_number": {
          "type": "string"
        },
        "amount": {
          "type": "number",
          "minimum": 0
        },
        "currency": {
          "type": "string",
          "enum": ["BRL", "USD", "EUR"]
        },
        "status": {
          "type": "string",
          "enum": ["pending", "paid", "cancelled"]
        },
        "issue_date": {
          "type": "string",
          "format": "date"
        },
        "due_date": {
          "type": "string",
          "format": "date"
        }
      }
    }
  }'

Exemplo 2: Schema com Objetos Aninhados

curl -X POST "https://api.../production/context/orders/type/order/schema" \
  -H "Authorization: Bearer {TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "schema": {
      "type": "object",
      "required": ["customer", "items", "total"],
      "properties": {
        "customer": {
          "type": "object",
          "required": ["name", "email"],
          "properties": {
            "name": {
              "type": "string",
              "minLength": 2
            },
            "email": {
              "type": "string",
              "format": "email"
            },
            "document": {
              "type": "string"
            }
          }
        },
        "items": {
          "type": "array",
          "minItems": 1,
          "items": {
            "type": "object",
            "required": ["product_id", "quantity", "price"],
            "properties": {
              "product_id": {
                "type": "string"
              },
              "quantity": {
                "type": "integer",
                "minimum": 1
              },
              "price": {
                "type": "number",
                "minimum": 0
              }
            }
          }
        },
        "total": {
          "type": "number",
          "minimum": 0
        },
        "status": {
          "type": "string",
          "enum": ["pending", "processing", "shipped", "delivered", "cancelled"]
        }
      }
    }
  }'

Resposta (201 Created ou 200 OK)

{
  "id": 1,
  "client_id": "9fc42fe9-a4fd-443c-8d49-b85ece2151b9",
  "environment": "production",
  "context": "orders",
  "type": "invoice",
  "schema": {
    "type": "object",
    "required": ["customer_id", "amount", "currency", "status"],
    "properties": { ... }
  },
  "created_at": "2024-01-15T10:30:00.000000Z",
  "updated_at": "2024-01-15T10:30:00.000000Z"
}

Obter Schemas

Endpoint

GET /api/v1/client/{client}/{environment}/context/{context}/type/{type}/schema

Exemplo

curl -X GET "https://document-hub-api-xp.wake.tech/api/v1/client/9fc42fe9-a4fd-443c-8d49-b85ece2151b9/production/context/orders/type/invoice/schema" \
  -H "Authorization: Bearer {SEU_TOKEN}"

Resposta (200 OK)

{
  "id": 1,
  "client_id": "9fc42fe9-a4fd-443c-8d49-b85ece2151b9",
  "environment": "production",
  "context": "orders",
  "type": "invoice",
  "schema": {
    "type": "object",
    "required": ["customer_id", "amount", "currency", "status"],
    "properties": { ... }
  },
  "created_at": "2024-01-15T10:30:00.000000Z",
  "updated_at": "2024-01-15T10:30:00.000000Z"
}

Resposta (404 Not Found)

Se não existe schema para este escopo:

{
  "message": "Not Found"
}

Deletar Schemas

Endpoint

DELETE /api/v1/client/{client}/{environment}/context/{context}/type/{type}/schema

Exemplo

curl -X DELETE "https://document-hub-api-xp.wake.tech/api/v1/client/9fc42fe9-a4fd-443c-8d49-b85ece2151b9/production/context/orders/type/invoice/schema" \
  -H "Authorization: Bearer {SEU_TOKEN}"

Resposta (204 No Content)

Schema deletado com sucesso. Sem corpo de resposta.

Comportamento

Após deletar o schema:

  • ✅ Documentos existentes não são afetados
  • ✅ Novos documentos não serão validados (qualquer estrutura aceita)
  • ✅ Você pode criar um novo schema a qualquer momento

Validação Automática

Como Funciona

Quando um schema está definido para um tipo de documento:

  1. Ao criar um documento (POST):

    • O campo data é validado contra o schema
    • Se inválido, retorna erro 422 com detalhes
  2. Ao atualizar um documento (PUT):

    • O campo data é validado contra o schema
    • Se inválido, retorna erro 422 com detalhes
  3. Operações em lote (POST /bulk):

    • Todos os documentos são validados
    • Se qualquer um falhar, nenhum é salvo (transação atômica)

Exemplo de Erro de Validação

Requisição

curl -X POST "https://api.../production/context/orders/type/invoice/INV-001" \
  -H "Authorization: Bearer {TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "environment": "production",
    "context": "orders",
    "type": "invoice",
    "key": "INV-001",
    "data": {
      "customer_id": "invalid-format",
      "amount": -100,
      "currency": "INVALID"
    }
  }'

Resposta (422 Unprocessable Entity)

{
  "message": "Schema validation failed",
  "errors": [
    {
      "property": "customer_id",
      "message": "Does not match the regex pattern ^CUST-[0-9]+$"
    },
    {
      "property": "amount",
      "message": "Must be greater than or equal to 0"
    },
    {
      "property": "currency",
      "message": "Does not have a value in the enumeration [\"BRL\",\"USD\",\"EUR\"]"
    },
    {
      "property": "status",
      "message": "The property status is required"
    }
  ]
}

Exemplos Práticos

Exemplo 1: Schema para Usuários

{
  "schema": {
    "type": "object",
    "required": ["name", "email", "role"],
    "properties": {
      "name": {
        "type": "string",
        "minLength": 2,
        "maxLength": 100
      },
      "email": {
        "type": "string",
        "format": "email"
      },
      "role": {
        "type": "string",
        "enum": ["admin", "user", "guest"]
      },
      "age": {
        "type": "integer",
        "minimum": 18,
        "maximum": 120
      },
      "phone": {
        "type": "string",
        "pattern": "^\\+?[1-9]\\d{1,14}$"
      },
      "address": {
        "type": "object",
        "properties": {
          "street": {"type": "string"},
          "city": {"type": "string"},
          "state": {"type": "string"},
          "zipcode": {"type": "string"}
        }
      }
    }
  }
}

Exemplo 2: Schema para Produtos

{
  "schema": {
    "type": "object",
    "required": ["sku", "name", "price", "stock"],
    "properties": {
      "sku": {
        "type": "string",
        "pattern": "^[A-Z]{3}-[0-9]{4}$"
      },
      "name": {
        "type": "string",
        "minLength": 1,
        "maxLength": 200
      },
      "description": {
        "type": "string",
        "maxLength": 1000
      },
      "price": {
        "type": "number",
        "minimum": 0,
        "multipleOf": 0.01
      },
      "stock": {
        "type": "integer",
        "minimum": 0
      },
      "category": {
        "type": "string",
        "enum": ["electronics", "clothing", "food", "books"]
      },
      "tags": {
        "type": "array",
        "items": {
          "type": "string"
        },
        "uniqueItems": true
      },
      "dimensions": {
        "type": "object",
        "required": ["width", "height", "depth"],
        "properties": {
          "width": {"type": "number", "minimum": 0},
          "height": {"type": "number", "minimum": 0},
          "depth": {"type": "number", "minimum": 0},
          "unit": {"type": "string", "enum": ["cm", "m", "in"]}
        }
      }
    }
  }
}

Exemplo 3: Schema para Logs

{
  "schema": {
    "type": "object",
    "required": ["timestamp", "level", "message"],
    "properties": {
      "timestamp": {
        "type": "string",
        "format": "date-time"
      },
      "level": {
        "type": "string",
        "enum": ["debug", "info", "warning", "error", "critical"]
      },
      "message": {
        "type": "string",
        "minLength": 1
      },
      "context": {
        "type": "object"
      },
      "user_id": {
        "type": "string"
      },
      "ip": {
        "type": "string",
        "format": "ipv4"
      },
      "user_agent": {
        "type": "string"
      }
    }
  }
}

Exemplo 4: Schema com Validações Condicionais

{
  "schema": {
    "type": "object",
    "required": ["type", "value"],
    "properties": {
      "type": {
        "type": "string",
        "enum": ["personal", "business"]
      },
      "value": {
        "type": "number",
        "minimum": 0
      },
      "document": {
        "type": "string"
      }
    },
    "if": {
      "properties": {
        "type": {"const": "business"}
      }
    },
    "then": {
      "required": ["document"],
      "properties": {
        "document": {
          "pattern": "^\\d{2}\\.\\d{3}\\.\\d{3}/\\d{4}-\\d{2}$"
        }
      }
    }
  }
}

JSON Schema Reference

Tipos de Dados (type)

TipoDescriçãoExemplo
stringTexto"Hello"
numberNúmero (inteiro ou decimal)42, 3.14
integerNúmero inteiro42
booleanBooleanotrue, false
objectObjeto JSON{"key": "value"}
arrayArray[1, 2, 3]
nullNulonull

Validações para Strings

PropriedadeDescriçãoExemplo
minLengthComprimento mínimo{"minLength": 2}
maxLengthComprimento máximo{"maxLength": 100}
patternRegex{"pattern": "^[A-Z]+$"}
formatFormato predefinido{"format": "email"}
enumLista de valores{"enum": ["A", "B"]}

Formatos suportados:

  • date-time: ISO 8601 date-time
  • date: Data (YYYY-MM-DD)
  • time: Hora (HH:MM:SS)
  • email: Email válido
  • ipv4: Endereço IPv4
  • ipv6: Endereço IPv6
  • uri: URI válida
  • uuid: UUID válido

Validações para Numbers

PropriedadeDescriçãoExemplo
minimumValor mínimo{"minimum": 0}
maximumValor máximo{"maximum": 100}
exclusiveMinimumMaior que (exclusivo){"exclusiveMinimum": 0}
exclusiveMaximumMenor que (exclusivo){"exclusiveMaximum": 100}
multipleOfMúltiplo de{"multipleOf": 0.01}

Validações para Arrays

PropriedadeDescriçãoExemplo
itemsSchema dos itens{"items": {"type": "string"}}
minItemsMínimo de itens{"minItems": 1}
maxItemsMáximo de itens{"maxItems": 10}
uniqueItemsItens únicos{"uniqueItems": true}

Validações para Objects

PropriedadeDescriçãoExemplo
propertiesDefine propriedadesVer exemplos acima
requiredPropriedades obrigatórias{"required": ["name"]}
minPropertiesMínimo de propriedades{"minProperties": 1}
maxPropertiesMáximo de propriedades{"maxProperties": 10}
additionalPropertiesPermite propriedades extras{"additionalProperties": false}

Combinadores

PropriedadeDescrição
allOfDeve corresponder a todos os schemas
anyOfDeve corresponder a pelo menos um schema
oneOfDeve corresponder a exatamente um schema
notNão deve corresponder ao schema

Casos de Uso Avançados

Caso 1: Diferentes Schemas por Ambiente

# Schema para production (mais restritivo)
curl -X POST "https://api.../production/context/orders/type/invoice/schema" \
  -H "Authorization: Bearer {TOKEN}" \
  -d '{
    "schema": {
      "type": "object",
      "required": ["customer_id", "amount", "currency", "status", "payment_method"],
      "properties": { ... }
    }
  }'

# Schema para development (mais flexível)
curl -X POST "https://api.../development/context/orders/type/invoice/schema" \
  -H "Authorization: Bearer {TOKEN}" \
  -d '{
    "schema": {
      "type": "object",
      "required": ["customer_id", "amount"],
      "properties": { ... }
    }
  }'

Caso 2: Evolução de Schema

V1 do schema (inicial):

{
  "schema": {
    "type": "object",
    "required": ["name"],
    "properties": {
      "name": {"type": "string"}
    }
  }
}

V2 do schema (adicionar campo opcional):

{
  "schema": {
    "type": "object",
    "required": ["name"],
    "properties": {
      "name": {"type": "string"},
      "email": {"type": "string", "format": "email"}
    }
  }
}

V3 do schema (tornar campo obrigatório):

{
  "schema": {
    "type": "object",
    "required": ["name", "email"],
    "properties": {
      "name": {"type": "string"},
      "email": {"type": "string", "format": "email"}
    }
  }
}

Caso 3: Validação Personalizada com Regex

{
  "schema": {
    "type": "object",
    "required": ["cpf", "phone", "postal_code"],
    "properties": {
      "cpf": {
        "type": "string",
        "pattern": "^\\d{3}\\.\\d{3}\\.\\d{3}-\\d{2}$",
        "description": "CPF no formato XXX.XXX.XXX-XX"
      },
      "phone": {
        "type": "string",
        "pattern": "^\\([0-9]{2}\\) [0-9]{4,5}-[0-9]{4}$",
        "description": "Telefone no formato (XX) XXXXX-XXXX"
      },
      "postal_code": {
        "type": "string",
        "pattern": "^\\d{5}-\\d{3}$",
        "description": "CEP no formato XXXXX-XXX"
      }
    }
  }
}

Boas Práticas

1. Defina Campos Obrigatórios

// ✅ Bom: Campos críticos são obrigatórios
{
  "type": "object",
  "required": ["customer_id", "amount", "currency"],
  "properties": { ... }
}

// ❌ Ruim: Tudo opcional
{
  "type": "object",
  "properties": { ... }
}

2. Use Validações Apropriadas

// ✅ Bom: Validações específicas
{
  "amount": {
    "type": "number",
    "minimum": 0,
    "multipleOf": 0.01
  },
  "email": {
    "type": "string",
    "format": "email"
  }
}

// ❌ Ruim: Sem validações
{
  "amount": {"type": "number"},
  "email": {"type": "string"}
}

3. Documente com Descriptions

{
  "properties": {
    "status": {
      "type": "string",
      "enum": ["pending", "paid", "cancelled"],
      "description": "Status do pagamento: pending (aguardando), paid (pago), cancelled (cancelado)"
    }
  }
}

4. Use Enums para Valores Fixos

// ✅ Bom: Enum previne erros de digitação
{
  "currency": {
    "type": "string",
    "enum": ["BRL", "USD", "EUR"]
  }
}

// ❌ Ruim: Aceita qualquer string
{
  "currency": {"type": "string"}
}

5. Valide Formatos

{
  "properties": {
    "email": {"type": "string", "format": "email"},
    "website": {"type": "string", "format": "uri"},
    "created_at": {"type": "string", "format": "date-time"}
  }
}

6. Limite Tamanhos

{
  "name": {
    "type": "string",
    "minLength": 2,
    "maxLength": 100
  },
  "description": {
    "type": "string",
    "maxLength": 1000
  },
  "tags": {
    "type": "array",
    "maxItems": 10
  }
}

Troubleshooting

Erro 422 - Validation Failed

Sintomas:

{
  "message": "Schema validation failed",
  "errors": [...]
}

Solução:

  1. Leia os erros retornados
  2. Corrija os dados conforme o schema
  3. Tente novamente

Schema Não Está Validando

Possíveis causas:

  1. Schema não foi criado para este escopo exato
  2. Schema foi deletado
  3. Erro no formato do schema JSON

Verificação:

# Verifique se o schema existe
curl -X GET "https://api.../schema" \
  -H "Authorization: Bearer {TOKEN}"

Como Testar um Schema

# 1. Crie um schema de teste
curl -X POST "https://api.../testing/context/test/type/sample/schema" \
  -H "Authorization: Bearer {TOKEN}" \
  -d '{"schema": {...}}'

# 2. Tente criar um documento válido
curl -X POST "https://api.../testing/context/test/type/sample/doc-001" \
  -H "Authorization: Bearer {TOKEN}" \
  -d '{
    "environment": "testing",
    "context": "test",
    "type": "sample",
    "key": "doc-001",
    "data": { /* dados válidos */ }
  }'

# 3. Tente criar um documento inválido (deve falhar)
curl -X POST "https://api.../testing/context/test/type/sample/doc-002" \
  -H "Authorization: Bearer {TOKEN}" \
  -d '{
    "environment": "testing",
    "context": "test",
    "type": "sample",
    "key": "doc-002",
    "data": { /* dados inválidos */ }
  }'

Recursos Externos

JSON Schema

Ferramentas Online

  • JSON Schema Generator: Gere schemas a partir de exemplos JSON
  • JSON Schema Validator: Valide seus schemas online

What’s Next