michael-rubel/laravel-safe-request
A Laravel package for safer request handling: define validation rules and access only validated input, keeping unvalidated fields out of controllers and services. It helps reduce mass-assignment and untrusted-data risks while keeping form requests simple.
Architecture fit. Unchanged. The package still targets a narrow, well-defined seam in Laravel: the FormRequest lifecycle, making validated data the default accessor surface via a trait. It remains additive, opt-in per request class, and requires no service provider, config, or middleware. It does not replace the validator; it changes what the validator's output is allowed to influence. Nothing in 2.0.1 touches this.
Integration feasibility. Materially improved. The prior assessment's main integration gate was a stale Composer constraint — a January 2023 release would most likely declare ^9.0 and fail resolution on Laravel 10. The 2.0.1 changelog explicitly adds Laravel 10 support, so the one-line composer require + use SafeRequest; path is now viable on Laravel 10 without an immediate fork. Two caveats remain: (1) Laravel 11 and 12 are still unaddressed, so the same fork-and-widen work is merely deferred to the next upgrade rather than avoided; (2) the release is a patch version, so confirm it widened the constraint rather than dropping Laravel 9 — narrowing a constraint in a patch release would be a semver violation and a signal about release hygiene. Also confirm the PHP constraint moved in step; a Laravel 10 constraint paired with php: ^8.0 is fine, but worth reading.
Technical risk. The lifecycle component of the risk drops from "high" to "moderate"; the behavioral component is unchanged and now the dominant concern:
merge()-injected values, route/query parameters accessed through the same object, input() on keys absent from the rules array — will begin returning null rather than data. Failures here are quiet, not loud.validated() semantics for nested/optional keys, wildcard rules, and sometimes rules are exactly where narrowing surprises appear. Nothing in the changelog suggests the override list changed, but "no entry in the changelog" is not evidence — read the 2.0.0...2.0.1 diff and confirm it is composer.json plus CI only.Key questions.
all() only, or also input(), only(), get(), __get(), merge()? Is the override list exhaustive and stable?composer.json constraints for PHP and illuminate/* in 2.0.1? Did the release widen to ^9.0|^10.0 or drop ^9.0? Did the PHP constraint change?composer.json, CI, and the README? Any change to the trait's override list or return semantics must be treated as a behavioral change regardless of version number.$request->file() access, $request->route() parameters, or values injected via merge()/middleware?sometimes, and nullable rules — does a key absent from the rules array vanish entirely?Stack fit. Unchanged. Suitable only for applications that (a) already route all controller input through FormRequest and (b) read request data in controllers/services via the request object rather than via validated() assigned to a DTO. Applications that already call $request->validated() explicitly — or that map to DTOs/VMs — gain almost nothing and take on behavioral risk for no benefit. The package's value is essentially "enforcement for teams that forget to call validated()."
Migration path. The fork is no longer the forced route on Laravel 10, but it remains the recommended one for anyone planning to stay on Laravel past the next major. The choice is now time-horizon dependent:
composer require michael-rubel/laravel-safe-request, add the trait. Justified if the team is on Laravel 10, the repo has characterization tests per overridden method, and someone owns re-evaluating at the Laravel 11 upgrade. Accept that the fork happens later rather than never.app/Http/Requests/Concerns/, add MIT attribution, widen constraints in-house. Cost is minutes; it removes abandonware risk entirely, gives us ownership of the override list, and lets us add our own tests. Because the package is MIT and dependency-free, this is legally and technically clean.If the team's actual objective is "stop unvalidated fields reaching Eloquent," an equivalent outcome is achievable through stricter discipline ($request->validated() at every call site, or a FormRequest::toDto() convention) without any new abstraction. The trait's real benefit is default-safe behavior for new contributors — worth having, and now cheaper to try before owning.
Compatibility. Laravel 10 is claimed supported as of 2.0.1; verify rather than assume. Confirm CI actually exercises Laravel 10 (matrix entry, not just a constraint), then verify against the target minor the team runs. Laravel 11/12 remain unsupported by declaration and must be treated as fork-required. Pin an explicit test matrix: one test per overridden method, per Laravel minor version we support.
Sequencing.
sometimes, and file-upload cases. Write these before adoption either way — they are the artifact that survives whichever route you pick.merge() behavior explicitly.FormRequest classes to include the trait, so adoption is enforced rather than remembered.Maintenance. Downgraded but not eliminated. A release exists and Laravel 10 resolves, so the immediate "will this install?" tax on the current stack is gone. The structural problem remains: one release in roughly two and a half years means no PHP minor-version bumps, no proactive compatibility work, and no security response. Under a Composer dependency, the tax recurs at every framework upgrade — the question is now "when," not "whether." Under a vendored trait, maintenance drops to near zero, but ownership is 100% ours, including a test matrix. Budget a few hours per Laravel major upgrade to re-verify the override list against upstream changes either way.
Support. Unchanged and still the weakest dimension. No maintainer SLA, no issue triage commitment, no stated release cadence. 2.0.1 demonstrates the maintainer is reachable but does not establish an obligation to respond. Internal support means whoever adopts it becomes the de facto owner — acceptable for a 15-line trait, uncomfortable for a dependency on the input trust boundary.
Scaling. Runtime impact is effectively nil: no service provider boots, no I/O, no config lookups; the trait only changes which in-memory array is read. It scales linearly with request volume like any other method delegation. The scaling concern is organizational — the more request classes adopt it, the larger the surface a single behavioral change (or framework change) affects at once. Adoption should remain incremental for that reason.
Failure modes.
null; consumers may persist defaults or nulls without error. Symptom is wrong data, not an exception. Unchanged by the release.Request class produces a hard error at class load — loud, and caught quickly. This is the failure mode you will hit at Laravel 11.composer install. Deferred, not removed. Low severity, discovered at build time, but it blocks upgrades until addressed — expect it at Laravel 11.validated() discipline elsewhere. The trait is a safety default, not a security boundary — treat it that way.Ramp-up. Very low. Any Laravel developer understands FormRequest and traits; the concept is explainable in a paragraph ("the request object now only exposes validated fields"). The ramp-up cost is documentation, not training: the two things that must be written down are (1) which methods are overridden, and (2) how to access intentionally-unvalidated data (route params, files, headers) when the trait is in place. Without (2), new contributors will hit confusing nulls and work around the trait rather than with it. Add a third now: (3) the package's support horizon, so nobody assumes Laravel 12 works because 10 does.
Verdict (revised). 2.0.1 removes the objection that blocked adoption outright and shifts the recommendation from "the package is not [worth adopting]" to "adopt, but budget for ownership." The dependency is now defensible on Laravel 10 for teams with characterization tests and a named owner; vendoring the MIT trait remains the better call for teams on Laravel 11+, teams that want to decide once rather than twice, and any team that reads "one release in two and a half years" as the operative fact rather than "Laravel 10 is supported." The behavioral risk — silent narrowing on the input trust boundary — is unchanged by this release, so the mitigation that matters is still the per-method test matrix, not the constraint line. Re-evaluate on the next Laravel major or if a security advisory appears, whichever comes first.
How can I help you explore Laravel packages today?