Weave 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

illuminate/json-schema

Official Laravel JSON Schema component for defining and validating structured JSON data with a fluent, framework-native API. Part of the Illuminate suite, it offers a clean, expressive way to describe schemas and ensure payloads conform, making it ideal for APIs, configuration, and more in Laravel a...

View on GitHub
Deep Wiki
Context7

Getting Started

illuminate/json-schema ships inside laravel/framework (namespace Illuminate\JsonSchema), so a Laravel 11/12 app already has it — no install step. For a standalone/non-Laravel context, composer require illuminate/json-schema and bind Illuminate\JsonSchema\JsonSchemaFactory yourself.

Read these first, in order:

  1. src/Illuminate/JsonSchema/JsonSchemaFactory.php — the entry point behind the JsonSchema facade (Illuminate\Support\Facades\JsonSchema, accessor json-schema). It exposes the type constructors: string(), integer(), number(), boolean(), array(), object(), enum(), anyOf()/union(), any().
  2. src/Illuminate/JsonSchema/Types/Type.php — the shared base: title(), description(), default(), examples(), enum(), const(), nullable(), and toArray().
  3. Types/ObjectType.php, ArrayType.php, StringType.php, NumberType.php — the type-specific constraint methods (properties(), required(), items(), minLength(), pattern(), minimum(), …).

The package is a schema builder, not a validator: it produces a JSON Schema (draft 2020-12 shaped) array via ->toArray(). Your first useful thing is a schema for a payload you already validate by hand:

use Illuminate\Support\Facades\JsonSchema;

$schema = JsonSchema::object()
    ->properties([
        'name'  => JsonSchema::string()->minLength(1)->maxLength(120),
        'email' => JsonSchema::string()->format('email'),
        'age'   => JsonSchema::integer()->minimum(0),
        'tags'  => JsonSchema::array()->items(JsonSchema::string())->uniqueItems(),
    ])
    ->required(['name', 'email'])
    ->additionalProperties(false)
    ->toArray();

// hand to OpenAPI, an LLM tool definition, opis/json-schema, etc.

Implementation Patterns

Wrap schemas in small, named builder classes. Don't scatter fluent chains through controllers. A final class CreateUserSchema { public static function make(): Type { ... } } gives you one place to version and test. Snapshot ->toArray() in a test so schema drift is visible in diffs.

Reuse sub-schemas rather than repeating them. Build leaf types once (an AddressSchema, a MoneySchema) and splice them into parents via properties([...]), items(...), or anyOf([...]). Because types are plain objects, this composes cleanly and keeps required() lists close to the properties they describe.

LLM tool / structured-output definitions. This is the highest-leverage day-to-day use: the fluent API maps almost 1:1 onto function-calling JSON Schema. Emit ->toArray() as the tool's parameters, keep description() on every property (models use it), and set additionalProperties(false) aggressively so the model can't invent keys. Pair with a validation pass on the model's response before trusting it.

OpenAPI / API contract generation. Generate request and response schemas from the same builders used by your FormRequests, then feed them into your OpenAPI generator. This keeps docs and runtime expectations from diverging — the classic failure mode is hand-maintained YAML drifting from real validation.

Validation pipeline. Since the package stops at schema generation, wire toArray() into Opis\JsonSchema\Validator (or justinrainbow/json-schema) in a dedicated JsonSchemaValidator service, and cache the compiled schema object per request/schema class. A typical flow: build schema → validate raw array → hand the clean array to a DTO/Data::from(). Keep this separate from Laravel's Validator; mixing rule-based and schema-based validation in one class makes failures hard to attribute.

Schema-driven UI and form generation. Emit the same schema to the frontend and render fields from it; enum(), default(), format(), and required give you enough metadata for basic form rendering without a second source of truth.

Config and payload guards. For webhook receivers or queue payloads with a published contract, define the schema in code, validate on ingest, and log structured failures (opis gives you pointer paths like /user/email) instead of generic "invalid payload" errors.

Gotchas and Tips

  • required lives on the object, not the property. In JSON Schema, required is an object-level keyword. Use ->required(['a','b']) on ObjectType. If you see a per-property ->required() in examples, verify against Types/ObjectType.php in your installed version — semantics and the exact chaining style have shifted across framework releases.
  • additionalProperties defaults to permissive. Omitting it means "anything goes," which silently defeats the point of a schema. Set false explicitly on every object you care about, especially LLM tool schemas.
  • format is annotation-only for many validators. ->format('email') documents intent; opis and most engines won't enforce it unless you opt into format assertion. Enforce emails with Laravel's email rule or a pattern().
  • integer vs number matters. JsonSchema::integer() rejects 1.0 in strict validators; number() accepts both. Also remember PHP's json_encode will turn a float 1.0 into 1, which flips validation outcomes.
  • Empty arrays vs empty objects. JSON Schema properties must be an object. An empty PHP array encodes as [], not {}. If you build schemas dynamically and can end up empty, cast ((object) []) or ensure at least one property; otherwise validators reject the schema itself.
  • Nullability is not automatic. ->nullable() (or a union with JsonSchema::null()) is required; an optional property is absent, not null. This trips people coming from Laravel validation's nullable.
  • Don't confuse it with Illuminate\Validation\Rules\Json. That rule validates that a string is JSON; this package describes the shape of decoded data. They solve different problems.
  • Facade in tests. Resolve JsonSchemaFactory from the container (or inject JsonSchemaFactory) instead of calling the facade statically if you need to swap or extend type construction; the facade is a thin singleton and hard to fake otherwise.
  • Extension point: subclass Types\Type (and the relevant concrete type) if you need custom keywords, but check the factory for a registration hook first — the factory is the intended seam, and custom types can be lost if you resolve the factory multiple times without binding it as a singleton.
  • Debugging: dd($schema->toArray()) and paste into any JSON Schema validator playground. Nearly every "my schema doesn't validate" bug is a nesting error (properties placed under the wrong object) or a missing required, not a package bug.
  • Versioning: the package version tracks laravel/framework; the fluent surface is young and has changed. Pin your framework minor if you snapshot schemas in tests, and re-run those snapshots on upgrade.
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.
adachsoft/command-executor-lib
tagixo/document-builder
tagixo/page-builder
tagixo/mail-builder
tagixo/form-builder
primix/primix
tagixo/core
alesima/laravel-azure-service-bus
tomshaw/shopcart
likyly/laravel
darthsoup/shoppingcart
tdt/core
labyrinthe/connect-php
encore2/laravel-admin2
cboxdk/laravel-console-kit
shapecode/doctrine-dbal-datetimeutc
gilads-otiannoh254/inertia-protocol
dakiquang/laravel-oauth-refresh-lock
woda/laravel-worktrees
dalefranks/ramasite