← На главную

biff.graph — лёгкая альтернатива Pathom на 600 строк кода

07.07.2026 16:48 · hackernews

biff.graph — новая библиотека для Clojure, которая позволяет выстроить модель данных в виде запрашиваемого графа. Идея в том, чтобы единообразно обращаться и к базе данных, и к производным/вычисляемым данным через один и тот же механизм. Код модели разбивается на маленькие независимые куски — «резолверы» (resolvers). Прикладной код просто описывает форму нужных данных, не заботясь о том, откуда их брать. Это упрощает понимание и тестирование, особенно когда проект разрастается.

biff.graph — лёгкая версия Pathom, но без планировщика запросов. Из-за этого некоторые запросы могут выполняться не так эффективно, как в Pathom, зато сама библиотека занимает всего около 600 строк кода, а ядро выполнения запросов — около 200 строк. При этом поддерживаются батчевые резолверы и кеширование.

Автор (создатель Biff) давно использует Pathom в работе и побочных проектах, но не хотел включать его в Biff по умолчанию: для маленьких проектов и новичков порог входа слишком высок. biff.graph — попытка сделать ту же концепцию графового моделирования максимально доступной. Пользователю всё равно придётся освоить те же идеи, что и в Pathom, но разобраться в том, как библиотека работает внутри и как отлаживать код, будет проще.

Запросы в biff.graph используют слегка модифицированное подмножество EQL/Datomic pull. Резолверы — это функции, у которых заданы входной и выходной запрос. Функция получает данные в форме входного запроса и возвращает данные в форме выходного. После определения набора резолверов движок запросов собирает из них ответ в нужной форме.

Пример: определяются резолверы rss-feed и post (симулируют доступ к базе), затем резолвер clean-post-title, который берёт :post/title и возвращает :post/clean-title без эмодзи. Затем вызывается query, который возвращает данные, не заботясь о том, какие атрибуты из БД, а какие вычислены.

Для типовых таблиц рекомендуется авто-генерировать резолверы: один на тип сущности, вход — первичный ключ, выход — все атрибуты плюс join-ключи для внешних ссылок. Такие резолверы помечаются :batch true, чтобы БД могла загрузить несколько сущностей за раз. Функция резолвера делает фактически SELECT *.

После этого можно добавлять произвольные производные резолверы. Готовый набор передаётся в com.biffweb.graph/new-ctx, который создаёт индексы и оборачивает резолверы в middleware для кеширования и валидации. Запросы выполняются откуда угодно — хоть из обработчика Ring.

При ошибках в com.biffweb.graph/query в данные исключения добавляется ключ :biff.graph/trace, указывающий, в какой части графа произошёл сбой — это помогает быстро найти проблему.

Для тестирования резолверов можно напрямую вызвать функцию по ключу :biff.graph/resolve-fn, передав контекст с :biff.graph/input. Библиотека также интегрируется с biff.fx — эффекты внутри резолверов можно описывать как машины состояний biff.fx.

Модули регистрируются через (com.biffweb.graph/module), резолверы кладутся в вектор :biff.graph/resolvers. Если зарегистрирована схема приложения, biff.graph будет проверять, что выход резолверов ей соответствует.

Автор рекомендует раскладывать резолверы по папке model/, а для повторно используемых UI-компонентов, завязанных на модель данных, — в ui_components/. Можно даже возвращать hiccup прямо из резолвера.

Особый случай — глобальные резолверы без входного запроса, например, для фоновых задач или для извлечения данных из сессии. Для авторизации автор пока экспериментирует с «params-резолверами», которые принимают ID из пути/параметров, проверяют права и возвращают сущность как join (или выбрасывают исключение, или просто исключают из результата).

Читать оригинал →