Comments 12
Насколько я понял, у них в проекте уже активно использовался валидатор ajv, который производит валидацию по JSON Schema. Скорее всего, они также использовали дополнительные возможности ajv, например, валидацию типов OpenAPI (правда, автор пишет так, как будто ajv поддерживает OpenAPI без плагинов, но кажется, что это не так).
zod, с другой стороны, обладает более простым и понятным способом описания схем дня валидации.
Поэтому автор решил написать обёртку над ajv, которая позволяла бы описывать схемы как в zod, а под капотом строила бы JSON Schema и делегировала валидацию ajv.
P.S. Тоже не слышал про zod, в рабочем проекте пользуемся joi. У них с zod очень похожий формат описания схем.
Upd. Пока писал, автор ответил сам ниже.
Все так. По поводу openAPI. у нас не так чтобы прям advanced схемы. тип int32, nullable и что-то еще(не помню что) поддерживается самим ajv и нареканий нет (хотя после вашего коментария уже начал сомневаться).
P.S. можно у нас также создать билдер со своим ajv инстансом, в случае если стандартный не подходит, потому-что не мы валидируем схему, а ajv
import {create} from 'ajv-ts'
import customAjv from 'ajv-from-somePackage'
const s = create(customAjv(/** opts */))
// ваши схемы
как уже было написано в статье, у нас уже был ajv и тянуть еще один пакет для деклараций одного и того же быть бы слишком, к тому же у зода есть типы которые не поддерживаются в JSON-Schema (function, symbol, Map, Set)
Аналоги валидации(и построения) схем кроме зода есть:
joi
yup
runtypes
io-ts
можете посмотреть тренды этих валидаций, ajv несомненный лидер https://npmtrends.com/ajv-vs-joi-vs-yup-vs-zod
Рассматривали ли вы такой вариант:
https://googlefeud.github.io/ts-runtime-checks/
Это трансформатор для ts который позволяет проверять типы в рантайме. Для своего запуска требует модифицированный tsc.
Вам достаточно генерировать ts-типы из сваггер-спеки и все. Не нужно писать ни одной схемы. Там так же есть валидации в духе max-length.
Библиотека мало известна и требует кастомный компилятор, что бы заставить её работать. Но давайте рассмотрим только её API. Подходит ли оно под задачи проекта?
Не натыкались на это решение, в любом случае она не подходила, тк у нас уже есть json-schema написанные в обычном объекте. Повторюсь, у нас уже использовался ajv для валидации до того как мы написали данное решение. Плюс мы работаем с реальной схемой, в любой момент можно вызвать свойство schema и работать с полученным объектом напямую, и никаких кастомных компиляторов не надо :)
Смотрели на @sinclair/typebox ?
TypeBox is a runtime type builder that creates in-memory Json Schema
Смотрели, не выбрали тк нам надо из имеющейся схемы создавать типы для ts а не наоборот
А для чего вы делали тогда SchemaBuilder, который строит json схему в рантайме? Если у вас есть файлы схем, то зачем вам строить схему и выводить из нее ts типы через Infer? Я скорее всего что-то упускаю, можете более отписать проблему, что вы пытались решить.
зачем стоить схему и выводить из нее типы
Затем, что после валидации у нас должен возвращаться в тип, который мы описали. Например объект, который мы можем назвать "myObjSchema", должен будет сказать какой тип у этой переменной. Как минимум - это удобно, тк не нужно дублировать тип и схему, достаточно описать схему, тип уже будет валидным.
const myObjSchema = s.object({
a: s.number(),
b: s.string()
})
const parsed = myObjSchema.parse(data)
type P = typeof parsed // {a: number, b: string}
function doSmth(obj: P) {
// работа с уже валидным объектом тк до этого был вызван parse
}
doSmth(parsed)
для чего вы делали тогда SchemaBuilder, который строит json схему в рантайме?
Для того, чтобы создавать схемы простыми функциями, просто и декларативно. Думал, что это очевидно. ?
Плюс, мы не валидируем схему, это делает ajv. Мы же строим ее для того, чтобы отдать схему потом самому ajv.
Тогда почему TypeBox не подходит? Он именно и строит в итоге json схему. Которую можно скормить в ajv, у них даже пример для ajv есть готовый в README.
https://github.com/sinclairzx81/typebox?tab=readme-ov-file#ajv
import { Type } from '@sinclair/typebox'
import addFormats from 'ajv-formats'
import Ajv from 'ajv'
const ajv = addFormats(new Ajv({}), [
'date-time',
'time',
'date',
'email',
'hostname',
'ipv4',
'ipv6',
'uri',
'uri-reference',
'uuid',
'uri-template',
'json-pointer',
'relative-json-pointer',
'regex'
])
const validate = ajv.compile(Type.Object({
x: Type.Number(),
y: Type.Number(),
z: Type.Number()
}))
const R = validate({ x: 1, y: 2, z: 3 }) // const R = true
Хорошо бы добавиться в бенчмарк валидаторов https://github.com/moltar/typescript-runtime-type-benchmarks
Zod умер. Да здравствует ajv-ts