$schema
import { $schema, s} from "dreamkit";
With the $schema
constructor you can create schemas very easily and most importantly, these schemas can be reused throughout the application, especially in the params
option of $route, $settings, $session and $api.
Because most of the data tends to come from a limited schema (SQL/NoSQL), $schema
does not aspire to be able to build very complex schemas, since these complex schemas, in addition to not existing in a database, are not easy to represent with secure typing in a form.
To simplify the creation of schemas it is recommended to use s
, a simple alias for $schema
.
An important point to note about $schema
is the ability to deeply manipulate object properties with the methods: pick
, omit
, assign
, require
, deepPartial
, deepRequired
and deepNullish
.
Definition
class Type { title(value: string): this; nullable(): this; optional(): this; nullish(): this; required(): this; validate(input: any): any[]; test(input: any): boolean; assert(input: any): asserts input is any; refine(input: (input: any) => boolean | any[]): this; toJsonSchema(): any;}const $schema: { title(value: string): typeof $schema; object(props: Record<string, Type>): Type & { props: Record<string, Type>; findProp(name: string): Type | undefined; findPropOrFail(name: string): Type; pick(mask: Record<string, boolean>): Type; omit(mask: Record<string, boolean>): Type; assign(props: Record<string, Type>): Type; require(mask?: Record<string, boolean>): Type; deepPartial(self?: boolean): Type; deepRequired(self?: boolean): Type; deepNullish(self?: boolean): Type; }; array(type: Type): Type & { min(value: number): Type; max(value: number): Type; }; string(): Type & { min(value: number): Type; max(value: number): Type; length(value: number): Type; }; number(): Type & { min(value: number): Type; max(value: number): Type; integer(): Type; }; bool(): Type; file(): Type & { ext(value: string[]): Type; min(value: number | `${number}mb`): Type; max(value: number | `${number}mb`): Type; }; custom(assert: (value: any) => boolean): Type;};
const s: typeof $schema;
FAQ
Why another schema validator?
You may be tired of the number of libraries of this kind (e.g. zod, yup, valibot), but below I will explain some of the reasons for this decision.
In the initial stages of development, valibot was considered, but its user experience is diminished by its aggressive tree shaking system, and if there is one thing that DreamKit aims to stand out for, it is its UX.
Zod was another alternative, but its large size and performance deficiencies in TypeScript were important reasons for its discard.
Examples
String validation
import { $route, Input, s } from "dreamkit";import { createSignal } from "solid-js";
const type = s.string().min(3).max(5);
export default $route.path("/").create(() => { const [name, setName] = createSignal(""); return ( <> <Input value={name} onChange={setName} /> <p> {"errors: "} {JSON.stringify(type.validate(name()), null, 2)} </p> </> );});
Object manipulation
import { $route, ObjectType, s } from "dreamkit";import { createSignal, For } from "solid-js";
const object = s .object({ id: s.number().integer().min(1), }) .assign({ profile: { name: s.string() }, });
const schemas: Record<string, ObjectType<{}>> = { // { id: number } pickOnlyId: object.pick({ id: true }), // { id?: number, profile?: { name?: string } } deepPartial: object.deepPartial(), // { id?: number | null, profile?: { name?: string | null } | null } deepNullish: object.deepNullish(), // { profile: { name: string, age?: number } } assign: object .assign({ profile: { age: s.number().optional() } }) .pick({ profile: true }), // { id: number, profile: {}} omitName: object.omit({ profile: { name: true } }),};
export default $route.path("/").create(() => { const [schema, setSchema] = createSignal("pickOnlyId"); const [json, setJson] = createSignal(JSON.stringify({ id: 1 }, null, 2)); const errors = () => { let subject; try { subject = JSON.parse(json()); } catch { subject = {}; } return schemas[schema()].validate(subject); }; return ( <> Schema:{" "} <select onInput={(event) => setSchema(event.target.value)}> <For each={Object.keys(schemas)}> {(value) => <option>{value}</option>} </For> </select> <p> JSON Schema: <br /> <textarea style={{ height: "300px", width: "100%" }} disabled onInput={(event) => setJson(event.target.value)} > {JSON.stringify(schemas[schema()].toJsonSchema(), null, 2)} </textarea> </p> <p> Input: <br /> <textarea style={{ height: "300px", width: "100%" }} onInput={(event) => setJson(event.target.value)} > {json()} </textarea> </p> <p>Errors: {JSON.stringify(errors(), null, 2)}</p> </> );});