I am going to release new version of Quartet 9: Allegro data validation library.
I wanted to create library that will have four principles:
- simplicity
- minimalism
- similarity of schema and TypeScript type
- performance
Evaluation of the results
For this type
interface Message {
type: "subscribeAcknowledgement"
channel: string // with "channel" inside
data: {
id: string
symbol: string
price: number
count: number
accustic: number
size: number
mid: number
last: number
lastSize: number
network: number
open: number
high: number
low: number
volume: number
interest: number
change: number
percents: number
someNumber: number
grade: number
mark: number
velocity: number
length: number
height: number
width: number
}
}
We have such validation function:
// validator: (value: any) => value is Message
const validator = v<Message>({
type: "subscribeAcknowledgement",
channel: v.and(v.string, v.test(/channel/)),
data: {
id: v.string,
symbol: v.string,
price: v.number,
count: v.number,
accustic: v.number,
size: v.number,
mid: v.number,
last: v.number,
lastSize: v.number,
network: v.number,
open: v.number,
high: v.number,
low: v.number,
volume: v.number,
interest: v.number,
change: v.number,
percents: v.number,
someNumber: v.number,
grade: v.number,
mark: v.number,
velocity: v.number,
length: v.number,
height: v.number,
width: v.number
}
})
Lets compare it with one of the fastest library ajv
and with one of the most popular library joi
.
Ajv Validator:
const ajvValidator = ajv.compile({
type: "object",
required: ["type", "channel", "data"],
properties: {
type: {
type: "string",
enum: ["subscribeAcknowledgement"]
},
channel: {
type: "string",
pattern: "channel"
},
data: {
type: "object",
required: [
"id",
"symbol",
"price",
"count",
"accustic",
"size",
"mid",
"last",
"lastSize",
"network",
"open",
"high",
"low",
"volume",
"interest",
"change",
"percents",
"someNumber",
"grade",
"mark",
"velocity",
"length",
"height",
"width"
],
properties: {
id: { type: "string" },
symbol: { type: "string" },
price: { type: "number" },
count: { type: "number" },
accustic: { type: "number" },
size: { type: "number" },
mid: { type: "number" },
last: { type: "number" },
lastSize: { type: "number" },
network: { type: "number" },
open: { type: "number" },
high: { type: "number" },
low: { type: "number" },
volume: { type: "number" },
interest: { type: "number" },
change: { type: "number" },
percents: { type: "number" },
someNumber: { type: "number" },
grade: { type: "number" },
mark: { type: "number" },
velocity: { type: "number" },
length: { type: "number" },
height: { type: "number" },
width: { type: "number" }
}
}
}
});
Joi Validator:
const joiSchema = Joi.object({
type: Joi.equal("subscribeAcknowledgement").required(),
channel: Joi.string()
.pattern(/channel/)
.required(),
data: Joi.object({
id: Joi.string().required(),
symbol: Joi.string().required(),
price: Joi.number().required(),
count: Joi.number().required(),
accustic: Joi.number().required(),
size: Joi.number().required(),
mid: Joi.number().required(),
last: Joi.number().required(),
lastSize: Joi.number().required(),
network: Joi.number().required(),
open: Joi.number().required(),
high: Joi.number().required(),
low: Joi.number().required(),
volume: Joi.number().required(),
interest: Joi.number().required(),
change: Joi.number().required(),
percents: Joi.number().required(),
someNumber: Joi.number().required(),
grade: Joi.number().required(),
mark: Joi.number().required(),
velocity: Joi.number().required(),
length: Joi.number().required(),
height: Joi.number().required(),
width: Joi.number().required()
})
});
And now, benchmark for this case:
joi x 1,104 ops/sec ±15.76% (80 runs sampled)
Quartet 8 x 1,438 ops/sec ±9.27% (55 runs sampled)
ajv x 78,991 ops/sec ±2.81% (83 runs sampled)
Quartet 9: Allegro x 149,552 ops/sec ±5.54% (78 runs sampled)
Why is it so fast? Let's look at it
validator.toString()
What we see is an actual result:
function validator(value) {
if (value == null) return false
if (value.type !== "subscribeAcknowledgement") return false
if (!validator.custom(value.channel)) return false
if (value.data == null) return false
if (typeof value.data.id !== 'string') return false
if (typeof value.data.symbol !== 'string') return false
if (typeof value.data.price !== 'number') return false
if (typeof value.data.count !== 'number') return false
if (typeof value.data.accustic !== 'number') return false
if (typeof value.data.size !== 'number') return false
if (typeof value.data.mid !== 'number') return false
if (typeof value.data.last !== 'number') return false
if (typeof value.data.lastSize !== 'number') return false
if (typeof value.data.open !== 'number') return false
if (typeof value.data.high !== 'number') return false
if (typeof value.data.low !== 'number') return false
if (typeof value.data.volume !== 'number') return false
if (typeof value.data.interest !== 'number') return false
if (typeof value.data.change !== 'number') return false
if (typeof value.data.percents !== 'number') return false
if (typeof value.data.someNumber !== 'number') return false
if (typeof value.data.grade !== 'number') return false
if (typeof value.data.mark !== 'number') return false
if (typeof value.data.velocity !== 'number') return false
if (typeof value.data.length !== 'number') return false
if (typeof value.data.height !== 'number') return false
if (typeof value.data.width !== 'number') return false
return true
}
Top comments (0)