tejadong/graphql-mutation-validator-bundle
GraphQL Mutation Validator Bundle adds reusable input validation to GraphQL mutations, letting you define rules and return consistent errors before resolvers run. A lightweight PHP/Symfony integration for safer, cleaner mutation handling with less boilerplate.
Install via Composer (verify constraints first, since the only documented release bump was PHP 7.3 compatibility and the package predates modern Laravel/PHP):
composer require tejadong/graphql-mutation-validator-bundle
Check composer.json on the repo for PHP/Laravel version bounds; the package name says "bundle" but the description claims Laravel's validator, so confirm which framework you are actually integrating with before wiring it in.
First place to look: the README in the repository root, then any config/, src/Attributes/ (or src/Annotations/), and src/ service provider/extension classes. Given the sparse release notes, the source is the real documentation—trace how a validation failure is converted into a GraphQL error and which resolver lifecycle hook runs it.
Register the provider/extension as the docs dictate (Laravel: add to config/app.php providers if not auto-discovered; Symfony: add the bundle to config/bundles.php). Publish any config file if a publish command is documented.
First use case: take one mutation that currently hand-validates arguments, e.g. a createUser(email, password) mutation. Declare rules next to it:
// illustrative shape—confirm exact API from source
#[Validate(['email' => 'required|email', 'password' => 'required|min:8'])]
public function createUser($_, array $args) { /* resolver */ }
Smoke test with a deliberately invalid payload in GraphiQL/GraphQL Playground. Confirm you get a structured errors array with per-field messages and that your resolver never executes. That proves the guard is actually wired.
Declare rules beside the resolver, validate centrally. The package's value is moving validation out of resolver bodies. Adopt a convention: every mutation that accepts user input carries a rule declaration, and resolvers assume arguments are already valid. No if (empty($args['email'])) guards.
Prefer the configuration/attribute style over annotations unless your toolchain already reads annotations at runtime (e.g. Doctrine Annotations). Attributes (or plain config arrays) are more portable and won't silently no-op if annotation reader isn't wired—verify which mechanism the installed version actually supports.
Reuse Laravel rule sets as a library. Build a small set of named rule groups (AuthRules, ProfileRules) and reference them from multiple mutations so validation stays consistent across create, update, and bulk variants. This is the main day-to-day leverage: one rule definition, many mutations.
Handle nested/array input deliberately. For mutations taking lists (e.g. items: [ItemInput]), use array-based rules like items.*.sku and confirm the package expands wildcards into per-index error keys. Test empty arrays and partially-valid lists explicitly, since array validation is the area most likely to behave unexpectedly.
Treat GraphQL errors as your contract. The package converts failures into structured errors automatically. Don't catch or rewrite them in resolvers; instead, document the error shape for clients (a validation entry with field paths) so frontends can map messages to form fields.
Layer authorization separately. Validation ≠ authorization. Keep permission checks in your resolver/policy layer; only shape and bounds validation belongs here. This keeps error semantics clean—invalid input vs. forbidden action.
In test suites, write one GraphQL mutation test per rule (missing, malformed, boundary-valid) asserting the structured error response. Because the package short-circuits before the resolver, you can assert errors without mocking downstream services.
Stale, low-signal package. Zero dependents, no stars, last release Jan 2021, and release notes only mention PHP 7.3. Expect no active maintenance, no modern-PHP CI evidence, and possible incompatibility with current Laravel/PHP. Pin an exact version and vendor the source if you must rely on it.
"Bundle" vs. Laravel validator naming clash. The repo name implies Symfony; the description claims Laravel's validator. Resolve this ambiguity before committing—read the service provider/extension class to see which framework container it hooks into. Getting this wrong is a hard dead end.
No documented install/config steps. The provided notes don't include a README, composer constraints, or publish tags. You'll be reverse-engineering from source. Budget time for this; treat every config key as unverified until you see it consumed.
Silent no-op risk with attributes/annotations. If the attribute/annotation reader isn't enabled, rules may simply not run—mutations succeed without validation and you won't notice. Add a test that asserts an invalid payload fails; if it passes, your declaration isn't being picked up. Check autoloading, attribute targets, and that the provider/extension is registered.
Debug order of failure. When a mutation returns an unexpected error, first confirm whether validation fired at all (add a temporary log inside the validator bridge or breakpoint the resolver). If the resolver ran, the package isn't in the pipeline; if it didn't, inspect the rule declaration and data shape.
Wildcard/array error paths. Nested and array rules are advertised but the exact error-key format (dot notation, index nesting) matters to clients. Snapshot-test the resolved error payload so a package/version difference doesn't silently change your API contract.
Extension points to inspect in source: custom rule registration, the validator service binding (so you can substitute Laravel's Validator or swap in a custom validator), and the exception/error converter (to adjust error codes or messages). These are where you'd patch around limitations—since upstream maintenance is unlikely, plan to fork and own these.
Upgrade/migration hygiene. Treat this as a legacy dependency: pin the version, run the full mutation test suite on any PHP/Laravel upgrade, and keep a documented fallback (hand-rolled validation) in case the package stops resolving against current dependencies.
How can I help you explore Laravel packages today?