Skip to main content

Schema validation (Draft 7)

JsonFlow includes a full Draft 7 JSON Schema validator. The primary class is TSchemaValidator (unit JsonFlow.SchemaValidator), which implements IJSONSchemaValidator.

Basic validation

uses
JsonFlow.SchemaValidator,
JsonFlow.Reader,
JsonFlow.Interfaces;

var
LReader: TJSONReader;
LValidator: TSchemaValidator;
LSchema, LData: IJSONElement;
begin
LReader := TJSONReader.Create;
LValidator := TSchemaValidator.Create;
try
LSchema := LReader.Read(
'{"type":"object",' +
'"properties":{"name":{"type":"string","minLength":2}},' +
'"required":["name"]}'
);
LData := LReader.Read('{"name":"A"}'); // will fail minLength

LValidator.ParseSchema(LSchema);

if not LValidator.Validate(LData) then
begin
for var LErr in LValidator.GetErrors do
WriteLn(LErr.Path + ': ' + LErr.Message);
end;
finally
LValidator.Free;
LReader.Free;
end;
end;

Validate from strings

// Both schema and data as strings
if not LValidator.Validate('{"name":"A"}', '{"type":"object","required":["name"]}') then
WriteLn(LValidator.GetLastError);

TValidationError fields

FieldTypeDescription
PathstringJSON Pointer to the failing data location
SchemaPathstringJSON Pointer to the failing schema keyword
MessagestringHuman-readable error description
FoundValuestringActual value that failed
ExpectedValuestringExpected value or constraint
KeywordstringSchema keyword that triggered the error
LineNumberIntegerSource line (when available)
ColumnNumberIntegerSource column (when available)
ContextstringAdditional context

Supported Draft 7 keywords

Type validation

type — string, number, integer, boolean, null, array, object

String keywords

minLength, maxLength, pattern, format

Number keywords

minimum, maximum, exclusiveMinimum, exclusiveMaximum, multipleOf

Array keywords

items, minItems, maxItems, uniqueItems, contains

Object keywords

properties, required, additionalProperties, patternProperties, propertyNames, minProperties, maxProperties

Composition keywords

allOf, anyOf, oneOf, not, if / then / else

Reference

$ref — resolves internal (#/definitions/...) and external references

Enumeration

enum

Built-in format validators

JsonFlow ships format validators for:

FormatUnit
dateJsonFlow.FormatValidators.Date
date-timeJsonFlow.FormatValidators.DateTime
timeJsonFlow.FormatValidators.Time
emailJsonFlow.FormatValidators.Email
ipv4JsonFlow.FormatValidators.Ipv4
ipv6JsonFlow.FormatValidators.Ipv6
uriJsonFlow.FormatValidators.Uri
uuidJsonFlow.FormatValidators.Uuid
cpf (Brazil)JsonFlow.FormatValidators.CPF
cnpj (Brazil)JsonFlow.FormatValidators.CNPJ
cep (Brazil)JsonFlow.FormatValidators.CEP
phone-br (Brazil)JsonFlow.FormatValidators.BrazilianPhone
license-plate-brJsonFlow.FormatValidators.BrazilianLicensePlate

Loading schemas from files

Use TJSONSchemaReader (unit JsonFlow.SchemaReader) to load a schema from a file:

uses
JsonFlow.SchemaReader;

var
LSchemaReader: TJSONSchemaReader;
begin
LSchemaReader := TJSONSchemaReader.Create;
try
LSchemaReader.LoadFromFile('path/to/schema.json');
// or: LSchemaReader.LoadFromString('{"type":"object",...}');

if not LSchemaReader.Validate('{"name":"Alice"}') then
begin
for var LErr in LSchemaReader.GetErrors do
WriteLn(LErr.Path + ': ' + LErr.Message);
end;
finally
LSchemaReader.Free;
end;
end;

TJSONSchemaReader public API:

MemberDescription
CreateDefault constructor (uses Draft 7 validator internally)
LoadFromFile(AFileName)Load and parse schema from a file; returns Boolean
LoadFromString(AJsonString)Load and parse schema from a string; returns Boolean
Validate(AJson)Validate JSON string against the loaded schema; returns Boolean
Validate(AElement)Validate IJSONElement against the loaded schema; returns Boolean
Validate(AJson, AJsonSchema)Validate JSON string with schema string in one call; returns Boolean
GetErrorsReturns TArray<TValidationError>
GetVersionReturns the detected TJsonSchemaVersion
GetSchemaReturns the loaded schema as IJSONElement

External $ref resolution

Implement IJSONSchemaRef and register it with the validator to resolve external $ref URIs:

uses
JsonFlow.Interfaces;

type
TMySchemaRef = class(TInterfacedObject, IJSONSchemaRef)
function FetchReference(const ARef: string): IJSONElement;
end;

Built-in HTTP resolvers are provided for Indy (JsonFlow.SchemaRefIndy) and Synapse (JsonFlow.SchemaRefSynapse).

Logging

LValidator.OnLog(
procedure(const AMsg: string) begin WriteLn(AMsg); end
);

Async validation