Вопрос или проблема
Я новичок в Clojure и решил попробовать Biff. Я создаю простой блог, но решил бросить себе вызов и использовать Postgres в качестве базы данных. Я следовал руководству по Postgres Biff, но обнаружил, что ключ :example/ds из контекста возвращает nil (я также удалил все, что блогу не нужно, например, аутентификацию).
; В моем основном файле проекта...
(defn use-postgres [{:keys [biff/secret] :as ctx}]
(let [ds (jdbc/get-datasource (secret :example/postgres-url))]
(assoc ctx :example/ds ds)))
; ...
(def components
[biff/use-aero-config
biff/use-queues
biff/use-jetty
biff/use-chime
biff/use-beholder
use-postgres])
; ... В файле моего блога:
(defn blog-home [{:keys [example/ds] :as ctx} & body]
(ui/page
ctx
[:h2 ""]
[:p "Это мой блог"]
[:.blog-list (generate-blog-entries (database/get-n-blog-posts ds 10))]
[:h3 "Конец списка блогов"]))
(defn blog-page [{:keys [path-params] :as ctx}]
(ui/page
ctx
))
(def module
{:routes ["/blog"
["/" {:get blog-home}]]})
Исключение, которое я получаю:
[qtp1087121050-39] ERROR com.biffweb.impl.middleware - Исключение при обработке запроса
java.lang.IllegalArgumentException: Не найдена реализация метода: :-execute-all протокола: #'next.jdbc.protocols/Executable для класса: nil
… и после некоторого отладки я обнаружил, что ds
в blog-home
всегда nil.
Я пытался добавить промежуточное ПО следующим образом:
(def module
{:routes ["/blog" {:middleware [mid/wrap-site-defaults]}
["/" {:get blog-home}]]})
… но это ничего не исправило.
Кроме того, смотря в REPL, я обнаружил, что ds всегда присутствует:
(defn get-context []
(biff/merge-context @main/system))
(defn add-fixtures []
(let [{:keys [example/ds] :as ctx} (get-context)
user-id (random-uuid)]
(log/info "Полный CTX: " ctx)
(log/info "Просто db: " (ctx :example/ds))
(comment
(jdbc/execute! ds ["INSERT INTO users (id, email, foo) VALUES (?, ?, ?)"
user-id "[email protected]" "Некое значение"])
(jdbc/execute! ds ["INSERT INTO message (id, user_id, text) VALUES (?, ?, ?)"
(random-uuid) user-id "Привет"]))))
И я получаю
#object[next.jdbc.connection$url_PLUS_etc$reify__29062 0x149be200 postgresql://tester:postgres@localhost:5433/xyz]
так что я правильно настраиваю JDBC и помещаю его в системную карту, он просто не отображается в get блога.
Ответ или решение
Чтобы правильно модифицировать контекст в Biff и устранить проблему с отсутствием значения для ключа :example/ds
, вам нужно обратить внимание на порядок инициализации компонентов, а также на то, как вы передаете контекст в разные функции.
Понимание проблемы
Основная причина, по которой :example/ds
возвращает nil
в функции blog-home
, заключается в том, что контекст, передаваемый в blog-home
, не содержит ожидаемого значения для ключа :example/ds
. Это может произойти, если функция, создающая datasource, не была выполнена до вызова вашего обработчика маршрута.
Шаги для решения проблемы
-
Порядок инициализации компонентов. Убедитесь, что
use-postgres
добавлен в массивcomponents
до любых других компонентов, которые могут использовать его контекст.(def components [biff/use-aero-config biff/use-queues biff/use-jetty biff/use-chime biff/use-beholder use-postgres]) ;; `use-postgres` должен быть первым
-
Проверка датасорса. Ваша функция
use-postgres
должна корректно создавать и добавлять datasource. Убедитесь, что URL вашего Postgres корректен и что база данных доступна. Проверьте, что ключ:example/postgres-url
действительно содержит требуемый URL.(defn use-postgres [{:keys [biff/secret] :as ctx}] (let [ds (jdbc/get-datasource (secret :example/postgres-url))] (if ds (assoc ctx :example/ds ds) (throw (ex-info "Datasource could not be created" {})))))
-
Проверка контекста в маршрутах. Убедитесь, что в рамках маршрутов вы используете правильный ключ для доступа к.datasource. Когда вы определяете функцию
blog-home
, строка{:keys [example/ds] :as ctx}
должна быть корректной. Попробуйте, например, просто вывести весь контекст, чтобы убедиться, что он содержит все ожидаемые данные:(defn blog-home [{:keys [example/ds] :as ctx}] (log/info "Контекст в blog-home: " ctx) (if ds (ui/page ctx [:h2 ""] [:p "This is my blog"] [:.blog-list (generate-blog-entries (database/get-n-blog-posts ds 10))] [:h3 "End blog list"]) (throw (ex-info "Datasource not available in blog-home" {}))))
-
Обработка middleware. Убедитесь, что ваше middleware не удаляет нужный контекст. Если вы используете
mid/wrap-site-defaults
, проверьте, как это middleware взаимодействует с вашим контекстом.
Общие рекомендации
- Логи. Обязательно логируйте ключевые моменты — это поможет вам увидеть, когда и где значения в контексте меняются.
- Тестирование. Попробуйте запустить минимальные тесты, чтобы изолировать и проверить только функции, которые работают с контекстом.
- Документация. Не забудьте проверить документацию Biff и Next.jdbc, чтобы быть уверенными в правильности реализации.
Заключение
Внесение изменений в контекст в Clojure Biff требует внимательности к порядку инициализации компонентов и тщательной проверки доступности данных. Следуя представленным шагам, вы сможете устранить проблему с отсутствием datasource и обеспечить корректную работу вашего блога на Postgres.