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 data against JSON Schema in PHP. Supports draft-3, draft-4, draft-6, and draft-7 with $ref resolution and detailed validation errors. Install via Composer and validate decoded JSON objects against local or remote schemas.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require justinrainbow/json-schema
    

    Add to composer.json if using Laravel's autoloader:

    "autoload": {
        "psr-4": {
            "App\\": "app/",
            "JsonSchema\\": "vendor/justinrainbow/json-schema/src/"
        }
    }
    

    Run composer dump-autoload.

  2. First Use Case: Validate an incoming API request payload:

    use JsonSchema\Validator;
    
    $validator = new Validator();
    $data = json_decode(request()->getContent(), true);
    $schema = json_decode(file_get_contents('schemas/user.json'), false);
    
    $validator->validate($data, $schema);
    
  3. Quick Validation Check:

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

Implementation Patterns

API Request Validation

Workflow:

  1. Define Schema: Store schemas in resources/schemas/ (e.g., user.json):

    {
        "type": "object",
        "properties": {
            "name": { "type": "string", "minLength": 2 },
            "email": { "type": "string", "format": "email" }
        },
        "required": ["email"]
    }
    
  2. Validate Request:

    public function store(Request $request) {
        $validator = new Validator();
        $schema = json_decode(file_get_contents('schemas/user.json'));
        $data = $request->all();
    
        $validator->validate($data, $schema, Constraint::CHECK_MODE_COERCE_TYPES);
        if (!$validator->isValid()) {
            return response()->json(['errors' => $validator->getErrors()], 400);
        }
        // Proceed with logic...
    }
    
  3. Reusable Validator Service:

    // app/Services/SchemaValidator.php
    class SchemaValidator {
        public function validate($data, string $schemaPath, int $flags = Constraint::CHECK_MODE_NORMAL) {
            $validator = new Validator();
            $schema = json_decode(file_get_contents($schemaPath));
            $validator->validate($data, $schema, $flags);
            return $validator;
        }
    }
    

    Usage:

    $validator = app(SchemaValidator::class)->validate($request->all(), 'schemas/user.json');
    

Form Request Validation

Extend Laravel's FormRequest:

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

class StoreUserRequest extends FormRequest {
    public function validateSchema() {
        $validator = new Validator();
        $schema = json_decode(file_get_contents('schemas/user.json'));
        $validator->validate($this->all(), $schema, Constraint::CHECK_MODE_COERCE_TYPES);

        if (!$validator->isValid()) {
            throw new \Exception('Validation failed: ' . json_encode($validator->getErrors()));
        }
    }
}

Dynamic Schema Loading

Cache Schemas:

// app/Providers/AppServiceProvider.php
public function boot() {
    SchemaStorage::getInstance()->addSchema(
        'file://schemas/user',
        json_decode(file_get_contents('schemas/user.json'))
    );
}

Resolve References:

$validator = new Validator(new Factory(SchemaStorage::getInstance()));
$validator->validate($data, (object)['$ref' => 'file://schemas/user']);

Type Coercion and Defaults

Automate Data Transformation:

$validator->coerce($data, $schema); // Shorthand for coercion
$validator->validate($data, $schema, Constraint::CHECK_MODE_APPLY_DEFAULTS);

Example:

$data = ['active' => 'true', 'age' => '25'];
$schema = (object)[
    'type' => 'object',
    'properties' => (object)[
        'active' => (object)['type' => 'boolean', 'default' => false],
        'age' => (object)['type' => 'integer', 'default' => 18]
    ]
];
$validator->validate($data, $schema, Constraint::CHECK_MODE_COERCE_TYPES | Constraint::CHECK_MODE_APPLY_DEFAULTS);

Testing

Unit Tests:

use JsonSchema\Validator;
use PHPUnit\Framework\TestCase;

class UserSchemaTest extends TestCase {
    public function testValidUser() {
        $validator = new Validator();
        $data = ['name' => 'John', 'email' => 'john@example.com'];
        $schema = json_decode(file_get_contents('schemas/user.json'));

        $validator->validate($data, $schema);
        $this->assertTrue($validator->isValid());
    }
}

Feature Tests:

public function testApiValidation() {
    $response = $this->post('/api/users', ['name' => 'A', 'email' => 'invalid']);
    $response->assertStatus(400);
    $this->assertArrayHasKey('errors', $response->json());
}

Gotchas and Tips

Common Pitfalls

  1. Schema References:

    • Issue: $ref paths must be absolute (e.g., file://schemas/user#/definitions/role).
    • Fix: Use SchemaStorage to resolve references:
      $storage = new SchemaStorage();
      $storage->addSchema('file://schemas/user', $schema);
      $validator = new Validator(new Factory($storage));
      
  2. Type Coercion Side Effects:

    • Issue: CHECK_MODE_COERCE_TYPES modifies the original $data.
    • Fix: Clone data before validation:
      $validator->validate(clone $data, $schema, Constraint::CHECK_MODE_COERCE_TYPES);
      
  3. Draft Compatibility:

    • Issue: Not all Draft-7 features are supported (check Bowtie Report).
    • Fix: Use Draft-6 for full compatibility:
      $validator->validate($data, $schema, Constraint::CHECK_MODE_STRICT);
      
  4. Error Handling:

    • Issue: getErrors() returns nested arrays; flatten for API responses:
      $errors = collect($validator->getErrors())->pluck('message')->toArray();
      
  5. Performance:

    • Issue: Repeated schema loading is slow.
    • Fix: Cache schemas in Laravel's cache:
      $schema = Cache::remember('user_schema', 60, function() {
          return json_decode(file_get_contents('schemas/user.json'));
      });
      

Debugging Tips

  1. Detailed Errors: Enable verbose error messages:

    $validator->validate($data, $schema);
    foreach ($validator->getErrors() as $error) {
        dump($error['property'], $error['message'], $error['constraint']);
    }
    
  2. Schema Validation: Validate the schema itself:

    $validator->validate($schema, $metaSchema, Constraint::CHECK_MODE_VALIDATE_SCHEMA);
    
  3. Strict Mode: Use CHECK_MODE_STRICT for Draft-6 to catch edge cases:

    $validator->validate($data, $schema, Constraint::CHECK_MODE_STRICT);
    

Extension Points

  1. Custom Constraints: Extend JsonSchema\Constraints\AbstractConstraint to add custom validation logic.

  2. Format Validators: Override format checks (e.g., custom date formats):

    use JsonSchema\Constraints\Format\FormatChecker;
    
    class CustomFormatChecker extends FormatChecker {
        public function checkCustomFormat($value) {
            // Custom logic
        }
    }
    
  3. Schema Storage: Extend SchemaStorage to load schemas from databases or APIs:

    class DatabaseSchemaStorage extends SchemaStorage {
        public function addSchema($id, $schema) {
            // Fetch from DB instead of file
        }
    }
    

Laravel-Specific Tips

  1. Service Provider: Bind the validator to the container:

    $this->app->bind(Validator::class, function() {
        return new Validator(new Factory(SchemaStorage::getInstance()));
    });
    
  2. Middleware: Validate all requests:

    class ValidateSchemaMiddleware {
        public function handle($request, Closure $next) {
            $validator = app(Validator::class);
            $validator->validate($request->all(), $this->getSchema($request));
            if (!$validator->isValid()) {
                abort(400, $validator->getErrors());
            }
            return $next($request);
        }
    }
    
  3. Artisan Commands: Validate CLI input:

    $validator = new Validator();
    $data = json_decode($
    
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.
davejamesmiller/laravel-breadcrumbs
artisanry/parsedown
christhompsontldr/phpsdk
enqueue/dsn
bunny/bunny
enqueue/test
enqueue/null
enqueue/amqp-tools
milesj/emojibase
bower-asset/punycode
bower-asset/inputmask
bower-asset/jquery
bower-asset/yii2-pjax
laravel/nova
spatie/laravel-mailcoach
spatie/laravel-superseeder
laravel/liferaft
nst/json-test-suite
danielmiessler/sec-lists
jackalope/jackalope-transport