I am currently working on an Express route that requires validation of the request body using Zod. The challenge arises when I need to conditionally require certain fields based on the values in the "channels" field, which is an array of enums. While my current implementation works, I find it a bit verbose and would appreciate any suggestions for a more concise approach. Despite exploring options like discriminated union, I have not found a solution that efficiently handles arrays of values.
Here is the logic:
- The "userId" and "channels" fields are always mandatory.
- If "channels" includes "EMAIL", then email-related fields should also be required.
- If "channels" includes "SMS", then sms-related fields should be required.
- If "channels" includes "FEED", then feed-related fields should be required.
This is how I currently handle it:
const schema = z.object({
userId: z.string(),
channels: z.array(z.enum(["EMAIL", "SMS", "FEED"])).nonempty(),
});
// Definition of emailSchema, smsSchema, feedSchema...
const result = schema.safeParse(req.body);
if (!result.success) {
// Error handling...
}
let channelsSchema = z.object({});
if (result.data.channels.includes("EMAIL"))
channelsSchema = channelsSchema.merge(emailSchema);
if (result.data.channels.includes("SMS"))
channelsSchema = channelsSchema.merge(smsSchema);
if (result.data.channels.includes("FEED"))
channelsSchema = channelsSchema.merge(feedSchema);
const channelsResult = channelsSchema.safeParse(req.body);
if (!channelsResult.success) {
// More error handling...
}
// Processing the validated data...
I have come across examples involving refine and superRefine, but these seem even more complex. Any insights or alternative solutions would be greatly appreciated!
Thank you for your help!