Комментарии 9
Идея создания нового языка пришла мне в голову, когда я получил задачу описать ТЗ для подрядчика на разработку API. Передо мной встал вопрос: как легко и понятно описать требования к контрактам?
OpenAPI прекрасно читается и некоторые даже код по нему генерят
Если говорить именно о моей задаче описания ТЗ, то да, OpenApi вполне подходил. В том случае я не стал его использовать из-за моего личного к нему отношения. Я не считаю его читабельным.
Если говорить в общем о сравнении OpenApi и Scedel, то:
OpenApi протоколо-центричный. Это прекрасно для описания REST-апи, однако ограничивает его использование;
OpenApi использует YAML, что с одной стороны хорошо, так как YAML - это устоявшийся формат, с которым умеют работать все системы. С другой стороны, из-за подчинения синтаксису YAML, OpenApi становится очень объемным в описании сложных схем (такая же проблема, как и в JSON Schema)
Зачем разделение на типы и валидаторы? Как из нескольких валидаторов собрать один? Почему параметры валидаторов то в квадратных то в круглых скобках?
Невстроенные валидаторы нужны для доменно-специфичных вещей и переиспользования. Валидаторы сами по себе могут быть не очень читаемыми, и совмещение типа и валидатора вместе может вызывать сильную когнитивную нагрузку при чтении.
Несколько валидаторов в один сами по себе не собираются. Валидатор присоединяется к типу как констрейнт. Можно сказать, что пользовательский тип - это базовый тип + констрейнты. На тип можно навесить несколько констрейнтов:
validator String(alphaOnly) = this matches /[a-zA-z]+/
type Username = String(alphaOnly, min:3, max:10)Здесь я навесил на тип три констрейнта (один пользовательский и два встроенных), и, для удобства использования, дал этому сложному типу алиас
Как к этому алиасу добавить еще один констрейнт?
Это хороший вопрос, спасибо!
Изначально я планировал, что создавать валидаторы можно только для базовых простых скалярных типов.
Теоретически, можно было бы сделать так:
Username(anotherConstraint)Но не уверен, как сейчас отреагируют на такое библиотеки, и это не описано в RFC.
Надо подумать, стоит ли давать возможность навешивать констрейнты на типы, производные от базовых. Здесь вопрос в том, не усложнит ли это интерпретацию кода пользователем
Констрейнты в квадратных скобках - специфичные для массивов ограничения
Email(domain:'gmail.com')[min:1]Здесь описан массив, состоящий из элементов типа Email(domain:'gmail.com'), в котором должен быть минимум один элемент. Можно написать чуть по-другому, так будет нагляднее
type GmailEmail = Email(domain:'gmail.com')
type User = {
emailsList: GmailEmail[min:1]
}Первым делом я подумал о JSON Schema, однако из-за её многословности я решил отказаться от неё, на мой взгляд, она недостаточно человекочитаема.
Интересный проект. Однако я год назад подумывал создать свой DSL, и проблема таких кастомных решений - это сложность их последующего расширения если вдруг понадобится использовать его для более широких целей, и такие языки к сожалению, становятся заложниками узких кейсов применения. Что касается JSON Schema то она и не призвана быть малословной, а скорее наоборот, многословность обусловлена высоким охватом практически любого кейса. И я не знаю какой кейс JSON Schema неспособна покрыть при должном знании спецификации. Разве что GraphQL и gRPC (но это отдельная история). Для удобства чтения - есть Swagger UI который идеально подходит для чтения.
Но, тем не менее, желаю успехов!

Scedel: DSL для описания схем данных