Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow simple extension of custom validators/sanitizers for better readability and reusability #1077

Closed
ysfaran opened this issue Aug 8, 2021 · 4 comments · Fixed by #1209
Milestone

Comments

@ysfaran
Copy link

ysfaran commented Aug 8, 2021

Is your feature request related to a problem? Please describe.

When I add a custom validator, which I need to reuse, I usually create a function like this:

export const isToken = (value) => {
  if (typeof value !== "string") {
    throw Error("Value must be a string");
  }

  if (!value.startsWith("0x")) {
    throw Error("Value  must start with '0x'");
  }

  if (value.length !== 42) {
    throw Error("Value must be 42 characters long");
  }

  return true;
};

Usage:

body("token").custom(isToken),

I use the snippet custom(isToken) above for a lot of validations and also reuse it for different middlewars like param instead of body. This unfortunatley breaks the cleanness of the fluent api and makes it harder to read. You also need to import isToken everywhere you use it. For customSanitizer it's quite similar.

Describe the solution you'd like

express-validator should allow to extend it's validators/sanitizers in an easier way, similiar to how jest does it with expect.extend.

A good solution would be to export new functions from the library:

import { extend } from "express-validator";

which will allow to add custom validators and sanitizers:

extend.validators({
  isToken,
});

extend.sanitizers({
  toSomeSanitizer: /*..*/,
});

Usage afterwards:

body("token").isToken().toSomeSanitizer(),

With this solution the API would look much cleaner and it would simplify reusability in contrast to custom or customSanitizer.

Implementation Idea

The feature could be implemented by extending the prototype of

export class ValidatorsImpl<Chain> implements Validators<Chain> {

export const extend = {
  validators(customValidators){
    for([name, validator] of Object.entries(customValidators)){
      // note: currently this.custom doesn't seem to support options
      ValidatorsImpl.prototype[name] = function(options) { return this.custom(validator, options); }
    }
  }
}
  
  // sanitizers() ...
}

It should also be supported to pass options to custom validators, e.g.:

export const isToken = (value, { length = 42 } = {} ) => {
  // ...

  if (value.length !== length) {
    throw Error(`Value must be ${length} characters long`);
  }

  return true;
};

body("token").isToken({ length: 18 }),

(I just had a rough look into to the code and there might be better ways to implement it. Feel free to suggest more appropriate solutions.)

@fedeci
Copy link
Member

fedeci commented Aug 8, 2021

I completely agree with you about this feature requirement, it is in the v7 roadmap right now, we just need to implement a solution😄

@ysfaran
Copy link
Author

ysfaran commented Aug 9, 2021

@fedeci great 😄 is the road map publicly visible somewhere?

@fedeci
Copy link
Member

fedeci commented Aug 9, 2021

Yes #990

@fedeci fedeci mentioned this issue Aug 9, 2021
9 tasks
ysfaran added a commit to ysfaran/express-validator that referenced this issue Aug 11, 2021
ysfaran added a commit to ysfaran/express-validator that referenced this issue Aug 14, 2021
@gustavohenke gustavohenke added this to the v7.0.0 milestone Feb 18, 2023
@gustavohenke gustavohenke linked a pull request Feb 18, 2023 that will close this issue
2 tasks
@gustavohenke
Copy link
Member

This is now possible in v7.0.0!
Check out docs here

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants