question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Option to create params from input in custom validation

See original GitHub issue

zod custom validation allows params to be passed in to the error object. It would be nice if these could be created based on the initial data.

That is, instead of this type signature: .refine(validator: (data:T)=>any, params?: RefineParams)

zod could use: .refine(validator: (data:T)=>any, params?: RefineParams | (data: T) => RefineParams

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Reactions:4
  • Comments:5 (4 by maintainers)

github_iconTop GitHub Comments

3reactions
colinhackscommented, Sep 17, 2020

This is now possible in Zod 2 (now in beta)

const dynamicRefine = z.string().refine(
    val => val === val.toUpperCase(),
    val => ({ params: { val } }),
  );

  console.log(dynamicRefine.safeParse('asdf'));

returns

{
    Error: [
      {
        code: 'custom_error',
        params: {
          val: 'asdf',
        },
        path: [],
        message: 'Invalid input.',
      },
    ];
  }

@tmtron this is a pretty advanced use case but it is possible. Internally .refine delegates to the more advanced ._refinement method which you can use to implement this. You can use this method without worrying about breaking changes, I consider it a part of the public API; it only starts with an underscore mostly because it’s a “power user” feature.

Some other context: in Zod 2 the errors property of a ZodError has been renamed to issues. This clarifies the confusing “error” vs “suberror” aspect of the previous naming.

const apiString = z.string();
  z.object({
    columns: z.record(z.string()),
    primaryKey: z.array(apiString.nonempty()).nonempty(),
  })._refinement((data, ctx) => {
    const invalidPks = data.primaryKey.filter(
      pk => !Object.keys(data.columns).includes(pk),
    );
    if (invalidPks.length) {
      ctx.addIssue({
        code: z.ZodIssueCode.custom,
        message: `Invalid PKs: ${invalidPks.join(', ')}`,
      });
    }
  });

As you can see there’s no need to return anything from _refinement(). If ctx.addIssue is called at any point during the execution of the refinement, the parse will fail. You can call ctx.addIssue multiple times to create multiple errors. You can also make this function async if you want to do your database fetches inside your refinement.

You need to manually provide the error code using the z.ZodErrorCode enum. This isn’t required in .refine because .refine only every throws a single ZodCustomIssue whereas `refinement lets you throw arbitrarily many issues of any kind. The error handling guide has more information on this.


@brabeji The approach above also enables what you were trying to achieve with .dynamicRefinement. Great job on that PR 👍

2reactions
colinhackscommented, Jul 17, 2020

Great idea. I’ll definitely do something like this. Might leave the .refine method as is but add a .refinement for more advanced use cases.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Pass input params to custom validation function ruby
1 Answer 1 ; # app/models/model_name.rb validate :validation_fcn_for_attr_1 validate :validation_fcn_for_attr_2 ; # app/models/model_name.rb ...
Read more >
Custom Validator with Parameters in Angular - TekTutorialsHub
We learned how to pass a parameter to a custom validator. First, we create a factory function, which accepts the parameter. The factory...
Read more >
Spring MVC Custom Validation - Baeldung
In this tutorial, we'll do just that; we'll create a custom validator to validate a form with a phone number field, and then...
Read more >
Add custom validations and actions - Testim overview
Using an Add custom validation step or an Add custom action step, you can create custom steps where you input your own parameters...
Read more >
Custom Rules - VeeValidate
You can recieve an object instead of an array for your validation rule by providing a paramNames array in the extend options (third...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found