Lighthouse: Define advanced validation rules through method reference

Created on 1 Nov 2018  路  12Comments  路  Source: nuwave/lighthouse

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

  • Where would those methods go?
  • What about default namespaces?
  • What is the expected signature?
  • How to differentiate them from built in rules?
enhancement

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

All 12 comments

@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") ?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

spawnia picture spawnia  路  3Comments

sadhakbj picture sadhakbj  路  4Comments

a-ssassi-n picture a-ssassi-n  路  3Comments

vine1993 picture vine1993  路  3Comments

spawnia picture spawnia  路  4Comments