picosv is pico schema validator (2.50 KB) based on JavaScript data types and written in vanilla JavaScript with no dependencies.
Usable on both the frontend and backend, this lightweight validator is able to validate JavaScript entities from schemas.
npm install picosv
Picosv is designed to be easy to use. Here's how to get started with schema creation and entities validation.
A schema in Picosv is an object that defines the structure of your data. The following types are supported: string, number (including bigint), boolean, array of primitives or objects, and objects themselves.
Here's a simple example:
import { picosv, string, number } from 'picosv';
const schema = {
name: string(),
age: number()
};
const picoSchema = picosv(schema);
And here's a more complex example with arrays and objects:
import { picosv, array, object, string, number, boolean } from 'picosv';
const schema = {
events: array(object({
type: string(),
content: object({
message: string(),
source: string(),
}),
})),
data: object({
foo: string(),
bar: number(),
}),
count: number(),
active: boolean(),
};
const picoSchema = picosv(schema);
- Only JS primitive types, arrays and objects are allowed
- Arrays with multiple types are not allowed (primitive or object)
- Empty arrays are not allowed
Primitives types can be defined with the following functions :
- string: string()
- number: number()
- bigint: bigint()
- boolean: boolean()
Examples :
import {string, number, bigint, boolean} from 'picosv';
const schema = {
a: string(),
b: number(),
c: bigint(),
d: boolean(),
}
Objects can be defined with the object()
function.
Object properties can be defined in two ways:
- generically using the
object()
function without parameter' - in detail by describing the properties of the object as a object function parameter
In the first case, the properties of the object will not be checked.
Generic example :
import {string, number, boolean, object} from 'picosv';
const schema = {
event: string(),
count: number(),
active: boolean(),
data: object(),
}
Detailed example :
import {string, number, boolean, object} from 'picosv';
const schema = {
event: string(),
count: number(),
active: boolean(),
data: object({
foo: 'string',
bar: 'number'
})
}
Arrays can be defined with the array()
function.
They are two types of arrays :
- Array of primitives (ex:
['foo', 'bar']
) - Array of objects (ex:
[{key: 'foo'}, {key: 'bar'}]
)
Primitive array example :
import {string, number, boolean, array} from 'picosv';
const schema = {
event: string(),
count: number(),
active: boolean(),
arr: array(string()),
}
Object array example :
import {string, number, boolean, object, array} from 'picosv';
const schema = {
event: string(),
count: number(),
active: boolean(),
arr: array(object({
key: 'string',
}))
}
Optional properties can be defined with the optional()
function.
All attributes can be optionals (primitives, objects, arrays), you just need to encapsulate the type declaration in a optional()
function call.
Primitive example :
import {string, number, boolean, optional} from 'picosv';
const schema = {
event: string(),
count: optional(number()),
active: boolean(),
}
Object example :
import {string, number, boolean, optional, object} from 'picosv';
const schema = {
event: string(),
count: number(),
active: boolean(),
data: optional(object({
foo: 'string',
bar: 'number'
}))
}
Array example :
import {string, number, boolean, optional, array, object} from 'picosv';
const schema = {
event: string(),
count: number(),
active: boolean(),
arr: optional(array(object({
key: 'string',
}))),
arr2: optional(array(string())),
}
To validate an object against a schema, simply call the validate function in your picosv schema instance and pass the object to validate. The function will throw an error if the object does not match the schema.
Here's an example:
import { picosv } from 'picosv';
const picoSchema = picosv(schema);
const object = {
events: [
{ type: 'foo', content: { message: 'hello world!', source: 'blu' } }
],
data: {
foo: 'test',
bar: 55
},
count: 42,
active: false
};
try {
picoSchema.validate(object);
} catch (error) {
console.error(error);
}
The library also provides Typescript type inference from your schemas.
Let's see how it's works :
First, declare your schema like this :
import {string, number, boolean, object, array} from 'picosv';
import type { FromSchema, SchemaType } from 'picosv';
const schema = {
event: string(),
count: number(),
active: boolean(),
data: object({
foo: string(),
bar: number(),
}),
arr: array(string()),
events: array(object({
type: string(),
content: {
description: string(),
author: string(),
valid: boolean(),
}
})),
} as const satisfies SchemaType;
Notice that the as const statifies SchemaType
will validate that our schema respects the type SchemaType
.
Then create your type :
type YourAwesomeType = FromSchema<typeof schema>;
And thats it ! You can use the schema inferred type on your objects.
const a: YourAwesomeType = {
count: 55,
active: false,
event: 'coucou',
data: {
bar: 55,
foo: "test",
infinite: {
infinity: 55
}
},
arr: ["foo", "bar"],
events: [{
type: "foo",
content: {
author: "blu",
description: "qwe",
valid: 42 // Error: Type 'number' is not assignable to type 'boolean'.
}
}]
}
Library | Size (Minified) | Size (Minified + Gzipped) | Bench (simple schema) | Bench (complex schema) |
---|---|---|---|---|
Ajv | 119.6 kb | 35.2 kb | 157,815,912 ops/sec | 51,951,659 ops/sec |
Picosv | 2.53 kb | 0.94 kb | 53,005,826 ops/sec | 5,918,499 ops/sec |
Zod | 60.9 kb | 14.2 kb | 5,089,661 ops/sec | 709,588 ops/sec |
Benchmark files are available in the src/benchmark
directory