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 Laravel Package

kherge/json

kherge/json is a PHP library for encoding and decoding JSON through a clean, object-oriented API. It adds validation, detailed error handling, and configurable formatting on top of PHP's native JSON functions, making data exchange safer and easier to manage.

Deep Wiki
Context7

Getting Started

composer require kherge/json

The package is a thin, opinionated wrapper around two well-known libraries: a JSON syntax linter and a JSON Schema validator. Its value is that it collapses "is this valid JSON?" and "does this JSON match my schema?" into two small, exception-driven APIs you can drop into a codebase without wiring up the underlying tools yourself.

Where to look first: open src/ and read the interfaces before the concrete classes — LinterInterface and ValidatorInterface (plus the matching exception classes under src/Exception/). The README examples are short; the interfaces tell you exactly which entry points exist (string, file, and already-decoded input variants). Confirm the exact method names against your installed version, since this package has been through several API revisions.

First use case — lint a JSON payload before you trust it:

use KHerGe\Json\Linter;
use KHerGe\Json\Exception\LintException;

$linter = new Linter();

try {
    $data = $linter->lintString($request->getContent());
} catch (LintException $e) {
    abort(400, 'Malformed JSON: ' . $e->getMessage());
}

// $data is now safe to hand to your application code

That's the 80% case: you have raw bytes from a request body, a .json config file, or a queue message, and you want a clean failure instead of json_decode() silently returning null.

The second use case is schema validation — the same shape, but with an exception type that carries a list of violations rather than a single parse error:

use KHerGe\Json\Validator;
use KHerGe\Json\Exception\ValidationException;

$validator = new Validator();

try {
    $validator->validateString($raw, $schemaJson);
} catch (ValidationException $e) {
    report($e);
    return response()->json(['errors' => $e->getErrors()], 422);
}

Implementation Patterns

Lint, then validate, then decode. These are three distinct failure modes and you want them separated. Linting catches malformed bytes; validation catches well-formed JSON that doesn't match your contract; decoding is what you do once both pass. Resist the urge to collapse them into one helper — the error messages are much more useful when you know which stage failed.

Bind the interfaces in a service provider. There is no Laravel auto-discovery here. Register the concrete classes as singletons so you're not re-instantiating them per call, and type-hint against the interfaces in your own code so you can swap in a fake during tests:

// AppServiceProvider::register()
$this->app->singleton(LinterInterface::class, Linter::class);
$this->app->singleton(ValidatorInterface::class, Validator::class);

Wrap it in a Form Request for API input. The cleanest integration point for request bodies is a base form request that overrides prepareForValidation() or a custom ValidatesJson trait: lint first, then run schema validation, and convert failures into Laravel validation errors. This keeps controllers thin and gives you a single place to change the failure response format.

Cache schemas, not lint results. Schema files are read from disk on every validateFile/validateString call. Load the schema once (config, repository class, or a small schema registry keyed by a route name) and pass the string in. Lint results are cheap and not worth caching; schema compilation is the expensive part.

Use the file-based helpers for boot-time checks. A common pattern is a small Artisan command that walks config/ and resources/ looking for .json files and lints each one. Run it in CI and as a pre-deploy step — it catches the "someone added a trailing comma and the app boots with a null config" class of bug before it reaches production.

Test with fixtures, not inline strings. Keep a directory of known-good and known-bad JSON documents (plus their schemas) and assert on the exception type rather than the message text. Messages come from the underlying linter/validator and will shift between versions; the exception class is your stable contract.

Decorate for logging. Because the library is interface-first, the easiest way to get observability is a decorator that implements LinterInterface/ValidatorInterface, calls the inner instance, and logs timing plus failure counts. That gives you a dashboard of "how often is our JSON actually broken?" without touching call sites.

Gotchas and Tips

The license is listed as NOASSERTION. Before adopting this in anything commercially distributed, read the actual LICENSE file in the repo. If the terms are unclear, the pragmatic fallback is to depend directly on the two libraries this package wraps — you lose maybe forty lines of convenience code and gain unambiguous licensing plus a maintained dependency.

The package is old and unlikely to be actively maintained. Check the PHP constraint against your runtime and, more importantly, check what version of the underlying JSON Schema validator it pins. Old versions often only support draft-04 schemas; if your schemas use if/then, const, or newer keywords, they will validate silently wrong (unknown keywords are typically ignored rather than rejected). Test a schema that should fail and confirm it actually does.

Lint and validate are not interchangeable. A document that lints clean can still fail validation, and a validation exception does not mean the JSON is malformed. Always wrap both in separate try/catch blocks with distinct exception classes, and never catch a generic \Exception around both — you'll lose the ability to return a 400 vs. a 422.

The wrapped exceptions may hide line/column info. Syntax errors from the underlying linter typically carry line and column numbers. If the wrapper's exception only exposes a message, check $e->getPrevious() — that's usually where the richer exception lives. This matters a lot when you're debugging a 200KB config file and "parse error" is all you get.

Relative paths resolve against the current working directory, not the file that called the helper. In Laravel, the CWD is public/ for HTTP requests and the project root for Artisan, so a validateFile('resources/schemas/x.json') that works in a command can break in a request. Use base_path() / storage_path() to build absolute paths and pass those in.

Watch memory on large documents. Both linting and validation parse the whole document, and validation holds a decoded tree plus the schema in memory. For anything in the multi-megabyte range, consider streaming lint (the underlying linter supports it) or rejecting the payload at the web server layer first.

Extension points are the interfaces. If you need to add draft support, change how $ref is resolved, or inject a custom URI retriever for remote schemas, the right move is to implement the validator interface yourself and delegate to the underlying library with your configuration. Don't subclass the concrete classes — they're thin and their internals are not a stable API.

Debugging tip: when a validation unexpectedly passes, dump the schema through json_decode($schema, true) and confirm it's what you think it is. Trailing-comma-free but structurally wrong schemas (e.g. "type": "object" inside the wrong nesting level) are the most common cause of "why is this not failing?" — the second most common is a $ref that silently resolves to nothing.

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.
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core