Search code examples
node.jstypescriptmongodbjoizod

At least one / minimum one field in Zod Schema Validation


I have implemented this code using JOI where the user has to send the userId and at least one of the keys from the body. How to implement the same using ZOD ??

  params: Joi.object().keys({
    userId: Joi.required().custom(objectId),
  }),
  body: Joi.object()
    .keys({
      name: Joi.string(),
      email: Joi.string().email(),
      password: Joi.string().custom(password),
    })
    .min(1),
};

Solution

  • I think there's no direct analog in zod but you can achieve this constraint using refine or superRefine

    Using refine your schema might look like:

    const schema = z.object({
      params: z.object({
        userId: z.string()
      }),
      body: z
        .object({
          name: z.string(),
          email: z.string().email(),
          password: z.string()
        })
        .partial()
        .refine(
          ({ name, email, password }) =>
            name !== undefined || email !== undefined || password !== undefined,
          { message: "One of the fields must be defined" }
        )
    });
    

    If the refine fails then you will get a ZodError with the message specified.

    A more general refine function that could be reused on an arbitrary partial object would be something like:

    const atLeastOneDefined = (obj: Record<string | number | symbol, unknown>) =>
      Object.values(obj).some(v => v !== undefined);
    

    I noticed there was custom parsing for the object id and the password. I think those could both be done with refine as well but I'm not familiar with how Joi custom validators work so I didn't want to write them with refine and have it be incorrect code.