Problem
In Laravel when we define rules, we have the option to do something like this Rule::unique('users')->ignore($user->id), or for a more advanced example this
Rule::unique('users')->where(function ($query) {
return $query->where('account_id', 1);
})
Rules like these are not possible to be defined in Lighthouse using the Rule directive.
Solution
If we add support for method references in the Rule directive, then we can simply reference a method which returns one of these advanced Rules.
For example we would be ale to write
@rules(apply : ["required", "min:3", "max:24", "updateUser@uniqueWithoutSelf"]
In the above example, when the rules directive hits a rule which is a method reference, then it should resolve the method and inject the result of the method to the validator instead of passing the string to the validator.
Considerations
@olivernybroe This is pretty interesting, what we could probably get away with is doing something like this:
@rules(apply: ["required", "min:3", "max:24"], methods: ["uniqueWithoutSelf"])
Alternatively, we could create a custom rule inside of lighthouse that accepts the method name which could look like:
@rules(apply : ["required", "min:3", "max:24", "lighthouse:uniqueWithoutSelf"])
The closure could be registered w/ a singleton in a service provider like so:
graphql()->rule("uniqueWithoutSelf", function () {
// ...
});
@chrissm79 Oh I like that a lot. I think that would be a great way to solve it.
However I think they will almost always be unique for only one endpoint.
So what about doing
graphql()->rule("User", 'uniqueWithoutSelf', function($data) {
// ...
});
So if 3 parameters are added, the rule is specific to that datatype, else it is available globally. If only 2 parameters, then it will be global rule.
This way you can have uniqueWithoutSelf defined multiple times, if you need different implementations, but not obfuscate your naming of rules.
Also if the type you add is a interface, then the rule is available for everything that implements that interface.
A thing more, just to add more cool stuff in case you have many custom rules.
graphql()->rule("User", UserRules::class);
This would mean that all methods in the class will be rules, based on the method name.
Not in love with the extra arg method since it breaks the ordering, which is important for validation.
What is wrong with the Laravel way of defining custom rules? https://laravel.com/docs/5.7/validation#using-extensions
Could also be another method called ruleForType.
But lets just keep it simple and we can always extend it if needed.
I think a good first solution which we can agree on is the one you suggested
graphql()->rule("uniqueWithoutSelf", function ($data) {
// ...
});
@olivernybroe This is pretty interesting, what we could probably get away with is doing something like this:
@rules(apply: ["required", "min:3", "max:24"], methods: ["uniqueWithoutSelf"])Alternatively, we could create a custom rule inside of lighthouse that accepts the method name which could look like:
@rules(apply : ["required", "min:3", "max:24", "lighthouse:uniqueWithoutSelf"])The closure could be registered w/ a singleton in a service provider like so:
graphql()->rule("uniqueWithoutSelf", function () { // ... });
This would be awesome. Extending validation like @spawnia mentions is just a workaround to call existing rules. There should be a less-redudant way I guess.
Would it be very difficult to implement the validation through form requests?
Within the form request it is easier to implement the more complex validations
@nachofassini one major challenge lies within handling the arbitrarily deep nested inputs that Lighthouse potentially accepts, for example when using nested mutations.
I don't know how Form Request classes could deal with that.
Closing this as https://github.com/nuwave/lighthouse/pull/812 allows using custom rule classes. Implementing a custom ArgValidationDirective is another viable option. https://lighthouse-php.com/master/custom-directives/argument-directives.html#argvalidationdirective
Any support for laravel form request yet?
Want something like this @rules("App\\Http\\Requests\\UserRequest")
@abdulmanan7 feel free to submit a PR.
@abdulmanan7 feel free to submit a PR.
I wish i could do that , just join larval and lighthouse :(
Please how to pass parameter in constructor with this graphql rules @rules("App\Rules\UserStepValidator") ?
Most helpful comment
Would it be very difficult to implement the validation through form requests?
Within the form request it is easier to implement the more complex validations