Created
December 1, 2022 21:05
-
-
Save plourenco/0ec255191dfd75789e3d5a396c06696b to your computer and use it in GitHub Desktop.
Validator comparison
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* eslint-disable no-console */ | |
import Ajv, { JTDDataType } from "ajv/dist/jtd"; | |
import Joi from "joi"; | |
import { z } from "zod"; | |
import yup, { ValidationError } from "yup"; | |
export type AuthResponse = { | |
investorId: string; | |
expiration: number; | |
}; | |
// Joi | |
// Advantage: quite popular, straightforward, organization | |
// Disadvantage: still requires types (AuthResponse) | |
export const joiSchema = Joi.object({ | |
investorId: Joi.string().required(), | |
expiration: Joi.number().optional(), | |
}); | |
// .options({ presence: 'required' }) may add required by default | |
const joiInput = { investorId: "pedro" }; | |
const result = joiSchema.validate(joiInput); | |
console.log(result.value); // value is any | |
console.log((joiInput as AuthResponse).investorId); // needs to be casted | |
// -------------------------------------------------------------------------------- | |
// Ajv | |
// Advantage: quite popular; TS-friendly: generates types within validation scope; | |
// uses JSON schema standard, generic, organization sponsored by mozilla/microsoft | |
// Disadvantage: somewhat complex | |
export const schema = { | |
type: "object", | |
properties: { | |
investorId: { type: "string" }, | |
expiration: { type: "number" }, | |
}, | |
required: ["investorId"], | |
}; | |
// self generated typings | |
type AjvAuthResponse = JTDDataType<typeof schema>; | |
const ajv = new Ajv(); // this Ajv instance would be used for the whole application | |
const validate = ajv.compile<AjvAuthResponse>(schema); | |
const ajvInput = { investorId: "pedro" }; | |
validate(ajvInput); // boolean | |
if (validate(ajvInput)) { | |
// from here on, the type of ajvInput is like schema | |
console.log(ajvInput.expiration); | |
} else { | |
console.log(validate.errors); // any errors, can be changed to a single error too | |
} | |
// -------------------------------------------------------------------------------- | |
// Zod | |
// Advantage: TS-friendly: parsing, so no types required, fields required by default | |
// Disadvantage: not an organization, one maintainer, not very mature (2020) | |
const zodSchema = z.object({ | |
investorId: z.string(), | |
expiration: z.number().optional(), | |
}); | |
try { | |
const zodTest = zodSchema.parse({ investorId: "pedro" }); | |
console.log(zodTest.investorId); // type is already of same shape | |
// console.log(zodTest.foo); // TS error - property does not exist | |
} catch (err) { | |
if (err instanceof z.ZodError) { | |
console.log(err.message); | |
} | |
} | |
// -------------------------------------------------------------------------------- | |
// Yup | |
// Advantage: TS-friendly: generates types, from 2014 | |
// Disadvantage: not an organization, mostly run by one maintainer | |
const yupSchema = yup.object({ | |
investorId: yup.string(), | |
expiration: yup.number(), | |
}); | |
try { | |
const yupResult = yupSchema.validateSync({ investorId: "pedro" }); | |
console.log(yupResult.expiration); // type is already of same shape | |
// console.log(zodTest.foo); // TS error - property does not exist | |
} catch (err) { | |
if (err instanceof ValidationError) { | |
console.log(err.message); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment