Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Json Schema Laravel Package

justinrainbow/json-schema

Validate JSON documents against JSON Schema in PHP. Supports Draft-3, Draft-4, Draft-6 and Draft-7 (coverage varies). Install via Composer and use JsonSchema\Validator to validate data with local file $ref schemas and inspect validation errors.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:
    composer require justinrainbow/json-schema
    
  2. Basic Validation:
    use JsonSchema\Validator;
    
    $validator = new Validator();
    $data = json_decode(file_get_contents('data.json'));
    $schema = json_decode(file_get_contents('schema.json'));
    
    $validator->validate($data, $schema);
    
    if ($validator->isValid()) {
        // Data is valid
    } else {
        foreach ($validator->getErrors() as $error) {
            logger()->error($error['message']);
        }
    }
    

First Use Case: API Request Validation

Validate incoming API requests (e.g., Laravel Request object) against a schema:

use Illuminate\Http\Request;
use JsonSchema\Validator;

$validator = new Validator();
$requestData = (object) [
    'name' => $request->input('name'),
    'email' => $request->input('email')
];

$schema = json_decode('{
    "type": "object",
    "properties": {
        "name": { "type": "string" },
        "email": { "type": "string", "format": "email" }
    },
    "required": ["name", "email"]
}');

$validator->validate($requestData, $schema);

Implementation Patterns

1. Schema Storage for Reusable Schemas

Cache schemas in a SchemaStorage for performance and reusability:

use JsonSchema\SchemaStorage;

$storage = new SchemaStorage();
$storage->addSchema('user', json_decode(file_get_contents('schemas/user.json')));
$storage->addSchema('product', json_decode(file_get_contents('schemas/product.json')));

$validator = new Validator(new \JsonSchema\Constraints\Factory($storage));

2. Type Coercion for HTTP Inputs

Automatically convert string inputs to expected types (e.g., "true"true):

$validator->coerce(
    (object) ['active' => "true", 'price' => "19.99"],
    (object) [
        "type" => "object",
        "properties" => [
            "active" => ["type" => "boolean"],
            "price" => ["type" => "number"]
        ]
    ]
);

3. Default Values for Missing Fields

Apply schema defaults dynamically:

$validator->validate(
    (object) ['name' => 'John'],
    (object) [
        "type" => "object",
        "properties" => [
            "name" => ["type" => "string"],
            "age" => ["type" => "integer", "default" => 18]
        ]
    ],
    \JsonSchema\Constraints\Constraint::CHECK_MODE_APPLY_DEFAULTS
);

4. Inline References for Modular Schemas

Use $ref for reusable components (e.g., nested objects):

$schema = json_decode('{
    "definitions": {
        "address": {
            "type": "object",
            "properties": {
                "street": {"type": "string"},
                "city": {"type": "string"}
            }
        }
    },
    "type": "object",
    "properties": {
        "user": {"$ref": "#/definitions/address"}
    }
}');

$storage = new SchemaStorage();
$storage->addSchema('file://schema', $schema);
$validator = new Validator(new \JsonSchema\Constraints\Factory($storage));

5. Laravel Integration: Form Request Validation

Extend FormRequest to validate against JSON Schema:

use JsonSchema\Validator;
use Illuminate\Foundation\Http\FormRequest;

class StoreUserRequest extends FormRequest
{
    protected function failedValidation(Validator $validator)
    {
        $jsonValidator = new Validator();
        $jsonValidator->validate($this->validated(), $this->schema());

        if (!$jsonValidator->isValid()) {
            throw new \Exception("JSON Schema validation failed: " . implode(", ", $jsonValidator->getErrors()));
        }
    }

    protected function schema()
    {
        return json_decode(file_get_contents('schemas/user.json'));
    }
}

6. Error Handling Middleware

Centralize schema validation in Laravel middleware:

use Closure;
use JsonSchema\Validator;

class ValidateJsonSchema
{
    public function handle($request, Closure $next)
    {
        $validator = new Validator();
        $validator->validate($request->all(), $this->schema());

        if (!$validator->isValid()) {
            return response()->json([
                'errors' => $validator->getErrors()
            ], 422);
        }

        return $next($request);
    }

    protected function schema()
    {
        return json_decode(file_get_contents('schemas/api.json'));
    }
}

Gotchas and Tips

1. Draft Compatibility Quirks

  • Draft 7 Support: Fully supported, but some features (e.g., contentMediaType, contentEncoding) may require explicit configuration.
  • Draft 4 vs. Draft 6/7: Keywords like const or contains behave differently. Test thoroughly when migrating schemas.
  • Strict Mode: Use CHECK_MODE_STRICT for Draft-6 to enforce full compliance (may break existing schemas).

2. Performance Pitfalls

  • Schema Caching: Avoid re-parsing schemas on every request. Cache SchemaStorage instances:
    $storage = app()->make(SchemaStorage::class); // Singleton in Laravel
    
  • Large Schemas: Complex schemas (e.g., with deep $ref chains) can slow validation. Profile with microtime(true):
    $start = microtime(true);
    $validator->validate($data, $schema);
    logger()->debug("Validation time: " . (microtime(true) - $start) . "s");
    

3. Type Coercion Caveats

  • Data Mutation: CHECK_MODE_COERCE_TYPES modifies the input object. Clone it first if immutability is required:
    $validator->coerce(clone $requestData, $schema);
    
  • Boolean Strings: "true"/"false" are coerced to booleans, but "yes"/"no" are not. Use custom constraints for edge cases:
    $validator->validate($data, $schema, Constraint::CHECK_MODE_COERCE_TYPES | Constraint::CHECK_MODE_TYPE_CAST);
    

4. Reference Resolution Issues

  • File URIs: Use file:// (not ./ or ../) for local schema references:
    $storage->addSchema('file://' . realpath('schemas/user.json'), $schema);
    
  • Circular References: The library handles them, but infinite loops can crash PHP. Test with:
    {
      "$ref": "#/definitions/self"
    }
    
  • Remote Schemas: Use http:// or https:// for external schemas, but handle failures gracefully:
    try {
        $storage->addSchema('https://example.com/schema.json', $schema);
    } catch (\JsonSchema\Exception\InvalidSchemaException $e) {
        logger()->error("Schema fetch failed: " . $e->getMessage());
    }
    

5. Debugging Tips

  • Detailed Errors: Enable CHECK_MODE_EXCEPTIONS for stack traces:
    $validator->validate($data, $schema, Constraint::CHECK_MODE_EXCEPTIONS);
    
  • Schema Validation: Validate schemas against themselves with:
    $validator->validate($schema, $schema, Constraint::CHECK_MODE_VALIDATE_SCHEMA);
    
  • Custom Constraints: Extend \JsonSchema\Constraints\AbstractConstraint for domain-specific rules (e.g., "email must be company domain").

6. Laravel-Specific Tips

  • Service Provider: Bind SchemaStorage and Validator in a service provider:
    public function register()
    {
        $this->app->singleton(SchemaStorage::class, function () {
            $storage = new SchemaStorage();
            $storage->addSchema('user', json_decode(file_get_contents('schemas/user.json')));
            return $storage;
        });
    
        $this->app->bind(Validator::class, function ($app) {
            return new Validator(new \JsonSchema\Constraints\Factory($app->make(SchemaStorage::class)));
        });
    }
    
  • Artisan Commands: Validate CLI inputs:
    use JsonSchema\Validator;
    use Symfony\Component\Console\Command\Command;
    use Symfony\Component\Console\Input\InputInterface;
    
    class ValidateCommand extends Command
    {
        protected function execute(InputInterface $input, OutputInterface $output)
        {
            $validator = new Validator();
            $data = json_decode($input->getArgument('json'), true);
            $schema = json_decode(file_get_contents('schema.json'));
    
            $validator->validate($data, $schema);
    
            if (!$validator->isValid()) {
                $output->writeln("<error>Validation failed:</error>");
                foreach ($validator->getErrors() as $
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle
atriumphp/atrium
sandermuller/package-boost-laravel
sandermuller/boost-skills
redaxo/core
yusufgenc/filament-api-forge
l3aro/rating-star-for-filament
leek/filament-subtenant-scope
anil/file-picker
broqit/fields-ai