maize-tech/laravel-remote-rule
Laravel Remote Rule lets you delegate field validation to a remote HTTP endpoint, turning its JSON response into standard validation errors. Share validation logic across services and apps without duplicating rules in every codebase.
composer require maize-tech/laravel-remote-rule. 2.2.0 adds Laravel 11.x support, so this is now installable on L11 apps — if you were previously pinned to ^10.0 you can bump. Confirm the illuminate/* constraint in composer.json before assuming older Laravel versions are still supported alongside 11.php artisan vendor:publish --provider="Maize\RemoteRule\RemoteRuleServiceProvider" — check the README for the exact tag) and review the generated config before writing rules.src/ top-down: the service provider (bindings + config merge), the main RemoteRule class, and the tests/ directory. The tests are the most accurate documentation of how rule payloads are shaped and evaluated.FormRequest::rules() alongside your static rules.Start with one rule set and one endpoint. Do not wire it into every form on day one — the value is in the dynamic cases, not in replacing 'required|string|max:255'.
Static + remote in one ruleset. Keep structural rules (required, array, exists) static and let the remote layer own the volatile, business-owned constraints. Mixing them in a single rules() array keeps the FormRequest readable and makes it obvious which rules can change without a deploy.
Per-tenant / per-version rulesets. Store rules keyed by tenant_id + a version column, resolve the active version at request time, and keep old versions so you can replay or audit a submission against the rules that were live when it was made. This is the pattern that justifies the package's existence.
Wrap retrieval in a repository. Never call the package or the DB directly from a controller. A small RuleSetRepository::forTenant($id): RemoteRule (or equivalent) gives you one place to add caching, fallbacks, and logging when a stored rule fails to parse.
Cache aggressively, invalidate on write. Rule lookups run on every request. Cache the resolved array per tenant/version (Cache::remember, key includes version) and bust it in the model observer or admin save action. Without this you have added a query to every validated request.
Fallback to defaults. Wrap resolution in a try/catch or rescue() and fall back to a hard-coded conservative ruleset. A malformed JSON column or a deleted rule row should degrade to "stricter than intended", never to "no validation".
Testing. Validate the resolved ruleset with standard Validator::make() assertions in unit tests, and cover the resolution layer separately (tenant with no ruleset, invalid rule string, cache hit/miss). Assert on the rules produced, not just pass/fail — that catches silent drops of unknown rule strings.
Admin surface. Rules are data now, so they need CRUD, a preview ("what does this ruleset do to this sample payload?"), and an audit log of who changed what. Budget for this; it is usually larger than the integration itself.
exists:users,email leaks data via error timing, regex can be a ReDoS vector, and in: can enumerate values. Restrict the editable rule vocabulary to an allow-list of rule names, or keep editing behind a trusted admin permission with review.Rule::unique(), Rule::when(), closures, and Password::defaults() cannot round-trip through JSON/DB. Stored rulesets are string-syntax only; anything conditional or object-based has to be composed in PHP and merged at runtime.max:2555 or required_if:type,foo,bar will validate in a way that looks fine until a specific payload hits it. Add a smoke test that every active stored ruleset parses and produces a non-empty rule array.:attribute in messages comes from the field name, not your ruleset. If you have per-tenant human labels, pass a $attributes array into the validator rather than trying to encode labels in the stored rules.nullable and implicit rules. nullable must precede other rules, and implicit rules (required, present) behave oddly on missing keys. Order stored rules as authored, don't sort them.$request->validate(), TrimStrings/ConvertEmptyStringsToNull middleware, and removed the app/Http/Kernel.php middleware registration. If your ruleset relies on '' vs null distinctions, confirm your middleware stack (now in bootstrap/app.php) still produces the input shape your rules assume.How can I help you explore Laravel packages today?