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

Laravel Json Schema Request Laravel Package

wt-health/laravel-json-schema-request

A Laravel package for validating incoming requests against JSON Schema definitions. Define schemas once, keep controllers clean, and get precise, standards-based validation errors for your API or application requests.

View on GitHub
Deep Wiki
Context7

Getting Started

v4.0.0 is a compatibility release with two breaking changes, so before writing any code confirm your app version:

  • Laravel 12 and 13 are supported; Laravel 11 is no longer supported. If you're still on Laravel 11, stay on v3.2.x and pin it in composer.json ("wt-health/laravel-json-schema-request": "^3.2") until you upgrade the framework.
  • Failed authorization now returns HTTP 403 (previously it surfaced as whatever the underlying guard/exception produced, typically 401/419 territory). Anything asserting status codes will need updating.

Minimal adoption steps:

  1. composer require wt-health/laravel-json-schema-request:^4.0 — check the resolution with composer update --dry-run first, since dropping Laravel 11 changes the constraint graph.
  2. Look first at vendor/wt-health/laravel-json-schema-request/src/ — the base request class and the service provider are the whole package surface. There is no elaborate config to learn.
  3. First use case: take one endpoint that already hand-validates a nested JSON payload with Validator::make() rules, and port it. Create a request class extending the package's base request, implement the schema method (returning the JSON Schema as a PHP array), and type-hint it on the controller method — Laravel resolves and validates it exactly like a FormRequest.

That single endpoint migration tells you everything: whether your schema dialect is supported, how errors are shaped, and whether your authorize logic behaves as expected under the new 403 semantics.

Implementation Patterns

Schema-per-endpoint request classes. Keep one request class per route, mirroring FormRequest conventions. The schema lives in a method returning a plain array — keep it declarative and free of $this calls so it can be extracted, cached, or snapshot-tested.

Extract shared fragments into files, not PHP duplication. Define reusable objects (addresses, money, pagination envelopes) once under resources/schemas/ and compose them with $ref. Resolving refs from disk keeps schemas readable and lets non-PHP tooling (editors, API contract tests, front-end validators) consume the same files. If the package resolves refs relative to a base URI you configure, set that base explicitly rather than relying on cwd.

Contract-first for write endpoints. JSON Schema's strength over Laravel's rule array is expressing shape: nested objects, arrays of objects, required at every level, additionalProperties. Use it for POST/PUT bodies where clients send real documents. Keep plain FormRequest for flat forms — you'll write more lines for less benefit.

Layered validation. Let the schema own shape (types, required keys, enums, nesting) and let a follow-up step own domain rules (uniqueness, existence, ownership). Schema validation that reaches into the database couples your contract to your data and produces errors that read like API errors rather than business errors.

Authorization as a guard, not a validator. Use the authorize hook for tenancy and ownership checks. With v4 returning 403, the semantics are crisp: "authenticated but not permitted." Keep authentication (401) in middleware and authorization here, and your status codes stay honest.

Version your schemas alongside migrations. When a payload shape changes, add a v2 schema file and route between them by API version header, rather than mutating the existing one. Cheap to do, and it prevents the "old mobile clients break" class of incident.

Test the contract, not the validator. Feature tests that postJson() a valid document and assert assertValid()/assertJsonValidationErrors() cover the behaviour. Add one test per schema that asserts an intentionally malformed payload fails — this catches accidental loosening (a stray additionalProperties: true, a forgotten required).

Gotchas and Tips

  • 403 is now the authorize-failure status. Audit tests asserting 401/419 on permission failures, any front-end interceptor that treats 403 as "hard forbidden / log out", and any API docs published with the old codes. If you have clients relying on 401, handle the mapping in your exception handler rather than pinning the package back.
  • Laravel 11 support is gone, not deprecated. v4 is a hard constraint bump. Check transitive dependencies first — a stale package requiring laravel/framework ^11 will make the solver fail in confusing ways.
  • Draft dialect differences bite. exclusiveMinimum as a boolean (draft-04) versus a number (draft-06+), $id versus id, and definitions versus $defs are not interchangeable. Pin the draft explicitly in your schema root and confirm which meta-schema the package validates against; a schema that "passes" in a linter may be interpreted differently at runtime.
  • Strict objects surprise people. JSON Schema's default allows unknown properties; only "additionalProperties": false rejects them. If you expect Laravel-style "unknown field = error," you must opt in — and then remember that adding a field client-side becomes a breaking change.
  • integer is not number. 1.0 fails integer in strict drafts, and PHP's JSON decoding will happily hand you a float. Normalize or widen the type rather than debugging a phantom 422.
  • format is annotation-only by default. email, date-time, uuid may not be asserted unless the validator is configured to check formats. Don't assume a format: email is enforced — add a test that proves it.
  • Error payloads differ from Laravel's validator. JSON Schema error output is a list of instance pointers (/user/addresses/0/postcode), not a dot-keyed message bag. If your front end consumes errors.field, add a mapping layer in the request class or a response macro; otherwise every consumer needs rewriting.
  • Ref resolution failures look like validation failures. A broken $ref path can produce a confusing schema-invalid error rather than a clean 500. When a request suddenly 422s on a schema you didn't touch, validate the schema document itself first.
  • Empty bodies and content types. POST with no body or a non-JSON content type may bypass or hard-fail depending on middleware ordering. Test both, and decide deliberately whether an empty object is valid.
  • Large schemas cost per-request parse time. If you have hot endpoints with deep ref graphs, compile or cache the resolved schema (a singleton in a service provider or a cached file) rather than resolving on every request; measure before optimizing, but keep the seam available.
  • Extension point: the base request class is the place to hang cross-cutting behaviour — a messages()-equivalent for human-readable errors, schema loading from files, or a trait for tenant-scoped $ref roots. Subclass once per project rather than editing vendor code, so the next major is a one-line constraint bump.
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.
takashato/laravel-vietqr
aitor24/laralang
kraenzle-ritter/entity-relations
dindigital/din-image
pomirleanu/image-colors
sawmainek/laravel-api-generator
delatbabel/jsonresponses
mouhamedfd/permissions-generator
eduplus/qr
laravel2580/idehelpers
delatbabel/viewpages
anavel/gettext
muhamadrezaar/highcharts
delatbabel/keylists
frankkessler/salesforce-laravel-oauth2-rest
anavel/foundation
wdmtech/enviricons
eii/laravel-captcha
muka/shape-reader
tdt/json