Не верим мы разработчикам и точка.
Или о том, как мы подошли к вопросу о валидировании схем
Обо мне
- SDET from 2018
- Senior SDET @b2broker
- certified node.js application developer
- TG - @haradkou_sdet

План
- Контекст проекта
- Паиплаин разработки
- С какой проблемой столкнулись
- Как решали
- К чему пришли
Контекст проекта
- Трейдинг терминал
- Документация
- Много интеграций
- Богатый API (Swagger)
- Есть WS (не swagger)
Трейдинг терминал

Фото из официального сайта b2broker.com/bbp
Документация
- Confluence
- IFR
- DFR
DFR
- Диаграммы
- Описание структур БД, полей
- Описание запросов и ответов
Проблема
- DFR может поменяться без изменения полей
- DFR может поменяться с изменением полей ответа
- Задача проводится как баг
- проверка занимает много времени для стендов (10+)
Решение

JSON schema
- много текста
- большая когнитивная нагрузка
- сложно\долго решаются конфликты
JSON Schema

JSON Schema

Ресерч!

Какие есть решения?
- ajv
- djv
- json-schema-library
- zod
- joi
- typebox
Чем выделяется zod?
import z from 'zod'
const Order = z.object({
orderId: z.string(),
items: z.array(z.object({
name: z.string(),
price: z.number(),
}))
})
type OrderApi = z.infer<typeof Order>
// {orderId: string, items: {name: string, price: number}[] }
Какие минусы
- Не являются имплементацией JSON-schema
- имеют поддержкку типов не характерные JSON-schema (function, bigint, symbol, ....)
- для генерации JSON-Schema нужно больше библиотек
AJV!
const Ajv = require("ajv")
const ajv = new Ajv()
const schema = {
properties: {
foo: {type: "int32"}
},
optionalProperties: {
bar: {type: "string"}
}
}
const data = {foo: 1, bar: "abc"}
const valid = ajv.validate(schema, data)
Плюсы ajv

- большое комьюнити
- широкое распростанение в продакшенах
- умеет в draft и swagger
- поддержка типов только характерных JSON-Schema
Минусы ajv
- длинное описание схем
- нужно читать не сверху вниз
Какой итог
- ajv
- нравится синтаксис zod
- генерировать json-schema - появилось в процессе

Что делаем?
export class SchemaBuilder {
_schema: any
/**
* returns JSON-schema representation
*/
get schema() {
return this._schema;
}
/**
* Marks your property as nullable (`null`).
*
* Updates `type` property for your schema.
* @example
* const schemaDef = s.string().nullable()
* schemaDef.schema // { type: ['string', 'null'], nullable: true }
*/
nullable(): SchemaBuilder {
// implementation
return this
}
}
Как используем?
// responseModels.ts
import s from 'ajv-ts'
const Order = s.object({
orderId: s.string(),
items: s.array(s.object({
name: s.string(),
price: s.number(),
}))
})
Order.schema
// {type: 'object', properties: { orderId: {type: 'string'} } }
export default {
'mySchema.Enteties.Order': Order
}
Генерируем!

Плюсы
- Декларативный и удобный API
- Есть JSDoc с примерами
- полная поддержка JSON-Schema
- можно подкинуть свой AJV инстанс
- поддержка pre/post parsing hooks
- Typescript runtime validation
- полная поддержка cjs/mjs
Минусы
- Малое распространение
- хайп на имени AJV
- работа с кастомными полями сделана не очень
- можно подменить свойство schema на свою в runtime
- нет three shaking (в планах)
- не поставляем .min.js
- скорость парсинга падает если использовать pre/post hooks
- прилось пойти на ухищрения TS (привет undefined)
Какие еще есть применения
- Парсинг .env переменных с использованием pre/post hooks
- валидация опций для cli утилит
А как попробовать у себя?

Bonus: Валидация min/max
import s from 'ajv-ts'
const Order = s.object({
orderId: s.string(),
name: s.string().min(5).max(2) // ! Typescript Error !
})
References
- Telegram - Haradkou.SDET
- Github - vitalics
- Github - vitalics/ajv-ts
Heisenbug 2024 Autumn
By vitalic gorodkov
Heisenbug 2024 Autumn
- 144