# JSON::Structure Perl SDK A native Perl implementation of the JSON Structure schema validation system. ## Overview JSON::Structure is a Perl SDK for validating JSON documents against JSON Structure schemas. It provides: - **Schema Validation**: Validate that a JSON Structure schema is well-formed - **Instance Validation**: Validate JSON data against a JSON Structure schema - **Source Location Tracking**: Get line and column numbers for validation errors - **Comprehensive Error Codes**: Standardized error codes matching other SDK implementations ## Requirements - Perl 5.20 or later - JSON::MaybeXS (for transparent JSON::XS acceleration when available) ## Installation ### From CPAN (when available) ```bash cpanm JSON::Structure ``` ### From GitHub Install directly from GitHub using cpanm: ```bash cpanm git://github.com/json-structure/sdk.git@perl-sdk ``` ### From Source ```bash git clone https://github.com/json-structure/sdk.git cd sdk/perl perl Makefile.PL make make test make install ``` ### Using cpanm with dependencies ```bash cd sdk/perl cpanm --installdeps . perl Makefile.PL make test ``` ## Command-Line Interface The SDK includes `pjstruct`, a command-line tool for schema and instance validation. ### Usage ```bash # Check if a schema is valid pjstruct check schema.struct.json # Validate an instance against a schema pjstruct validate -s schema.struct.json data.json # Validate multiple files pjstruct validate -s schema.struct.json *.json # Output in JSON format pjstruct validate -s schema.struct.json data.json --format=json # Output in TAP format (for test harnesses) pjstruct check *.struct.json --format=tap # Quiet mode (exit code only) pjstruct validate -s schema.struct.json data.json -q ``` ### Commands | Command | Alias | Description | |---------|-------|-------------| | `check` | `c` | Validate schema file(s) against the meta-schema | | `validate` | `v` | Validate instance file(s) against a schema | | `help` | | Show help for a command | | `version` | | Show version information | ### Options | Option | Short | Description | |--------|-------|-------------| | `--schema` | `-s` | Schema file (required for `validate`) | | `--format` | `-f` | Output format: `text`, `json`, `tap` (default: `text`) | | `--quiet` | `-q` | Suppress output, use exit code only | | `--verbose` | `-v` | Show detailed validation information | | `--help` | `-h` | Show help | | `--version` | `-V` | Show version | ### Exit Codes | Code | Meaning | |------|---------| | 0 | All files are valid | | 1 | One or more files failed validation | | 2 | Error (file not found, parse error, missing options) | ## Quick Start ### Schema Validation ```perl use JSON::Structure::SchemaValidator; use JSON::MaybeXS; # Create a validator my $validator = JSON::Structure::SchemaValidator->new(); # Parse your schema my $schema_text = '{"type": "string"}'; my $schema = decode_json($schema_text); # Validate the schema my $result = $validator->validate($schema, $schema_text); if ($result->is_valid) { print "Schema is valid!\n"; } else { for my $error (@{$result->errors}) { printf "Error at %s: %s (code: %s)\n", $error->path, $error->message, $error->code; } } ``` ### Instance Validation ```perl use JSON::Structure::InstanceValidator; use JSON::MaybeXS; # Define your schema my $schema = { '$schema' => 'https://json-structure.org/meta/core/v0/#', '$id' => 'https://example.com/person.struct.json', name => 'Person', type => 'object', properties => { name => { type => 'string' }, age => { type => 'int32' }, email => { type => 'string' } }, required => ['name', 'age'] }; # Your data to validate my $instance = { name => 'John Doe', age => 30, email => 'john@example.com' }; # Validate my $validator = JSON::Structure::InstanceValidator->new(schema => $schema); my $result = $validator->validate($instance); if ($result->is_valid) { print "Instance is valid!\n"; } else { for my $error (@{$result->errors}) { print "Validation error: " . $error->message . "\n"; } } ``` ## Supported Types ### Primitive Types | Type | Perl Validation | |------|-----------------| | `string` | String value | | `boolean` | JSON true/false (JSON::PP::Boolean) | | `int8`, `int16`, `int32`, `int64` | Integer within range | | `uint8`, `uint16`, `uint32`, `uint64` | Unsigned integer within range | | `float32`, `float64` | Numeric value | | `bytes` | Base64-encoded string | | `null` | undef or JSON null | ### Compound Types | Type | Description | |------|-------------| | `object` | Object with defined properties | | `array` | Homogeneous array of items | | `set` | Array with unique items | | `map` | Object as string-keyed dictionary | | `tuple` | Fixed-length typed array | | `choice` | Discriminated union | | `any` | Any JSON value | ### String Formats The SDK validates these string formats: - `date-time`, `date`, `time`, `duration` - `email`, `uri`, `uri-reference`, `uuid` - `ipv4`, `ipv6`, `hostname` - `json-pointer`, `regex` ## API Reference ### JSON::Structure::SchemaValidator ```perl my $validator = JSON::Structure::SchemaValidator->new(); my $result = $validator->validate($schema_doc, $source_text); ``` - `new()`: Create a new schema validator - `validate($schema, $source_text)`: Validate a schema document - `$schema`: Parsed JSON structure (hashref) - `$source_text`: Original JSON text (optional, for location tracking) - Returns: `ValidationResult` object ### JSON::Structure::InstanceValidator ```perl my $validator = JSON::Structure::InstanceValidator->new( schema => $schema, extended => 1, # Enable extended validation ); my $result = $validator->validate($instance, $source_text); ``` - `new(%options)`: Create a new instance validator - `schema`: The JSON Structure schema to validate against (required) - `extended`: Enable extended validation features (minLength, pattern, etc.) - `allow_import`: Enable processing of $import/$importdefs - `max_validation_depth`: Maximum recursion depth (default: 64) - `validate($instance, $source_text)`: Validate an instance against the schema - `$instance`: Parsed JSON data to validate - `$source_text`: Original JSON text (optional, for location tracking) - Returns: `ValidationResult` object ### JSON::Structure::Types ```perl use JSON::Structure::Types qw(ValidationResult ValidationError JsonLocation); # Create a validation result my $result = ValidationResult(\@errors, \@warnings); # Create a validation error my $error = ValidationError( code => 'INSTANCE_TYPE_MISMATCH', message => 'Expected string, got number', path => '/name', severity => SEVERITY_ERROR, location => JsonLocation(line => 1, column => 10), ); # Check result if ($result->is_valid) { ... } for my $err (@{$result->errors}) { ... } ``` ### JSON::Structure::ErrorCodes ```perl use JSON::Structure::ErrorCodes qw(:all); # or import specific groups: use JSON::Structure::ErrorCodes qw(:schema :instance); # Available constants: # Schema errors: SCHEMA_NULL, SCHEMA_INVALID_TYPE, SCHEMA_MISSING_TYPE, etc. # Instance errors: INSTANCE_TYPE_MISMATCH, INSTANCE_REQUIRED_MEMBER_MISSING, etc. ``` ## Error Handling All validation errors use standardized error codes that are consistent across all JSON Structure SDK implementations: ```perl use JSON::Structure::ErrorCodes qw(:all); my $result = $validator->validate($schema, $instance); for my $error (@{$result->errors}) { if ($error->code eq INSTANCE_TYPE_MISMATCH) { handle_type_error($error); } elsif ($error->code eq INSTANCE_REQUIRED_PROPERTY_MISSING) { handle_missing_field($error); } else { handle_generic_error($error); } } ``` ## Source Location Tracking When you provide the original JSON text, the SDK can report exact line and column numbers for errors: ```perl use JSON::Structure::JsonSourceLocator; my $locator = JSON::Structure::JsonSourceLocator->new($json_text); my $location = $locator->get_location('/path/to/element'); printf "Line %d, Column %d\n", $location->line, $location->column; ``` ## Testing ```bash # Run all tests prove -l t/ # Run with verbose output prove -lv t/ # Run specific test file prove -l t/02_schema_validator.t # Run with coverage cover -test ``` ## Publishing to CPAN See [PUBLISHING.md](PUBLISHING.md) for detailed instructions on publishing to CPAN. ## Integration with Test Assets The SDK can use the shared test assets for cross-SDK compatibility testing: ```perl use File::Spec; use JSON::PP; my $assets_dir = File::Spec->catdir('..', 'test-assets'); # Load and run test cases from shared assets ``` ## Contributing See the main [SDK-GUIDELINES.md](../SDK-GUIDELINES.md) for contribution guidelines and coding standards. ## License MIT License - see [LICENSE](LICENSE) for details.