clojure-russia 2018-09-03

Возвращаясь к валидации внешних данных: схема подошла как раз, только там коэрсии встроенные перед валидацией, а не после. Коэрсии после валидации впрочем дописываются на раз-два через schema.spec.core/run-checker и обратная конверия "нормальные типы -> JSON" тоже без проблем.

А как можно валидировать что-то до коэрции?

Очень просто. Схема говорит "здесь разрешен только строковый ключ такого вида", а коэрсия коэрсит его в какое-то внутреннее представление.

Например, схема может говорить "строка по регэкспу #"\d{2}INV-\d{8}#", а коэрсия превращает "77INV-08333333#" (без дополнительных проверок) в {:account/inventory-kind 8 :account/inventory-number 8333333}

Ну понятно, что можно проверить наличие или отсуствие каких-то полей или провести операции над строками. Но тебе ведь все равно это дело надо переводить во внутренее представление и еще раз проверять, но уже другие ствойства… Я для себя принял такой подход, сначала беру данные и пробую их коэрсить, а потом спекой валидирую уже внутрее представление данных, а не сериализованные. Мне кажется так оно понятней, ты или трансоформирушь данные или их валидируешь, разделение ответственности, что-ли…

У меня схема для внешних данных является, гм, схемой для внешних данных. Если валидация прошла, значит пришедший кусок данных валиден.

Пост-коэрсеры схемы внешних данных конвертируют внешние данные во внутреннее представление. Выход пост-коэрсера должен быть валидным внутренним представлением.

Спека описывает внутреннее представление, и это инвариант, который соблюдается внутри системы.

Обратно, перед сериализацией запускаются пре-декоэрсеры, которые конвертируют из внутреннего представления во внешнее, и результат проверяется схемой внешних данных, чтобы убедиться, что исходящее представление валидно.

Так что у меня три сущности: 1) схема внешних данных; 2) набор правил для перевода из внешнего представления во внутреннее, прицепленный к внешней схеме; 3) спека внутреннего представления.

Все правильно, я просто не понял зачем раунд валидации до коэрсии. Если данные не скоерсились - то они не пройдут валидацию внутренного представления… Разве что тебе важно поймать несоответсвие схемы внешних данных как можно скорее, по какой-то причине.

Мне важно поймать чуть-невалидные внешние данные. Например, если у меня есть коэрсия ключей "foo_bar" -> :foo-bar, то мне важно не пропустить ключ "foo-bar".

Вместо того, чтобы делать это в коэрсерах, я это делаю в схеме. Кроме того, спека требует дополнительных телодвижений для "в этой мапе только такие ключи, а других нет", а в схеме это естественно.

спасибо, что поделился

А вот, кстати, по поводу “в этой мапе только такие ключи, а других нет“. Как это решается? Я понимаю, что это противоречит концепции открытого мира, но все же интреесно как это обходится, если “очень нужно”

В спеке нужно руками проверять, а в схеме это модель по умолчанию.

Поэтому я и взял схему: она fail-closed, а не fail-open, как спека.

Ну собсно я и спрашиваю как это руками проверять? Есть какие-то практики или реально бегать по мапке с сравнимать каждый ключ…?

Я не видел готового. Потребовалось - сделал бы что-то вроде #(= (set (keys %)) #{...})

👍 1