opis/json-schema
Opis JSON Schema validates JSON documents against JSON Schema drafts 2020-12 to 06. Includes custom errors, PHP filters, schema reuse/mappers, slots, pointers, URI templates, $data, casting, and custom formats/media types.
Start by installing the package via Composer: composer require opis/json-schema. The core entry point is Opis\JsonSchema\Validator, which you use to validate JSON data against schemas. A minimal first use case: validate an API request payload.
use Opis\JsonSchema\Validator;
use Opis\JsonSchema\DataValidator;
use Opis\JsonSchema\Schema;
$validator = new Validator();
$schema = Schema::parse([
'type' => 'object',
'properties' => [
'email' => ['type' => 'string', 'format' => 'email'],
'age' => ['type' => 'integer', 'minimum' => 18],
],
'required' => ['email'],
]);
$result = $validator->validate($payload, $schema);
if ($result->isValid()) {
// proceed
} else {
foreach ($result->getErrors() as $error) {
echo $error->message() . PHP_EOL;
}
}
Head to the official documentation for quick start guides and API reference. The Validator::validate() method is your main interface — it accepts either a Schema instance or a JSON-serializable array.
Centralized Schema Registry: Cache compiled Schema objects (schemas are immutable after creation) and reuse them across requests or for common data shapes (e.g., user input, webhook payloads).
Laravel-style Validation: Wrap the validator in a service or macro to mimic Illuminate\Validation syntax:
$data = ['name' => 'John', 'age' => 25];
$schema = ['type' => 'object', 'properties' => [...]];
$errors = (new Validator())->validate($data, $schema)->getErrors();
Custom Filters for Business Logic: Use the $filters keyword to inject custom PHP callbacks for complex validations (e.g., cross-field rules) while keeping schemas expressive:
$schema = [
'type' => 'object',
'properties' => ['start' => [], 'end' => []],
'$filters' => [
'date_order' => fn($obj) => $obj->start < $obj->end
],
'date_order' => true
];
Hybrid Validation Pipeline: Combine JSON Schema with PHP-native type hints (e.g., DTOs with typed properties), letting the schema catch structural issues first, then let PHP enforce type safety.
Compliant Mode for Interop: Use Opis\JsonSchema\CompliantValidator when validating against public schemas to ensure strict compliance with the official JSON Schema spec (e.g., when supporting third-party integrations).
BCMath/Intl Impact: Floating-point comparison (e.g., multipleOf) relies on bcmath or intl. Set Helper::$useBCMath = true and/or ensure intl is enabled to avoid subtle rounding bugs. Use Helper::$numberScale for high-precision numeric tolerance.
String Length Nuances: Byte-based vs. grapheme-based length may vary depending on config. The maxLength keyword uses grapheme length by default — verify with Helper::stringLength() if validating user-facing strings.
Caching Schemas: Schema::parse() is expensive; always cache and reuse instances (e.g., static caches, Redis, or Laravel’s Schema::macro() patterns). The library supports lazy-loading via file loaders, but caching the parsed schema is critical for performance.
Error Customization: Use the $error keyword to override default messages in schemas — e.g., 'type' => 'string', '$error' => ['type' => 'Must be a string, please fix it.'].
Format Limitations: Built-in formats (like date-time) assume UTC unless timezone-aware strings are used. The library doesn’t auto-parse timestamps; validate format first, then convert in application logic.
Debugging Recursion: For large schemas, set Validator::setStopAtFirstError(true) to avoid expensive cascading errors. Use getErrors(true) with tree-mode to inspect nested sub-errors (e.g., for oneOf, anyOf).
Migrating from v1: If upgrading, follow the v2 migration guide — the API is largely rewritten, with Schema::load() replaced by Schema::parse(), and $data, $map, $filters now opt-in keywords.
How can I help you explore Laravel packages today?