diff --git a/project.clj b/project.clj index 3f34e09..0e16e80 100644 --- a/project.clj +++ b/project.clj @@ -8,6 +8,7 @@ [org.duct-framework/server.http.jetty "0.3.0"] [org.duct-framework/router.reitit "0.2.0"] [integrant "0.13.1"] + [hiccup "2.0.0-RC4"] [org.slf4j/slf4j-nop "2.0.16"] [org.webjars/normalize.css "5.0.0"] [ring/ring-core "1.13.0"] diff --git a/src/duct/middleware/web.clj b/src/duct/middleware/web.clj index abf6c6b..edca331 100644 --- a/src/duct/middleware/web.clj +++ b/src/duct/middleware/web.clj @@ -2,6 +2,7 @@ (:require [clojure.java.io :as io] [duct.logger :as logger] [integrant.core :as ig] + [hiccup2.core :as hic] [ring.middleware.defaults :refer [wrap-defaults]] [ring.middleware.stacktrace :refer [wrap-stacktrace]] [ring.middleware.webjars :refer [wrap-webjars]] @@ -67,6 +68,30 @@ (catch Throwable _ (respond (internal-error (error-handler request)))))))) +(defn- hiccup-response [response hiccup-renderer] + (let [response (if (vector? response) + {:status 200, :headers {}, :body response} + response)] + (if (vector? (:body response)) + (-> response + (update :body #(str "\n" (hiccup-renderer %))) + (assoc-in [:headers "Content-Type"] "text/html;charset=UTF-8") + (update :status #(or % 200))) + response))) + +(defn wrap-hiccup + "Middleware that renders vectors as HTML. The vector can either be the only + response from the handler, or on the body key of the response map. Requires + a function that converts Hiccup vectors into HTML." + ([handler] + (wrap-hiccup handler #(hic/html {:mode :html} %))) + ([handler hiccup-renderer] + (fn + ([request] + (some-> (handler request) (hiccup-response hiccup-renderer))) + ([request respond raise] + (handler request (comp respond hiccup-response) raise))))) + (defmethod ig/init-key ::log-requests [_ {:keys [logger options]}] #(wrap-log-requests % logger (dissoc options :logger))) @@ -90,3 +115,6 @@ (defmethod ig/init-key ::stacktrace [_ options] #(wrap-stacktrace % options)) + +(defmethod ig/init-key ::hiccup [_ {:keys [hiccup-renderer]}] + (if hiccup-renderer #(wrap-hiccup % hiccup-renderer) wrap-hiccup)) diff --git a/src/duct/module/web.clj b/src/duct/module/web.clj index 2e41fc1..ee74eb7 100644 --- a/src/duct/module/web.clj +++ b/src/duct/module/web.clj @@ -61,6 +61,8 @@ :duct.router/reitit {:routes ~routes ~@(when api? [:muuntaja {}]) ~@[] + ~@(when site? + [:data {:middleware [(ig/ref :duct.middleware.web/hiccup)]}]) ~@[] :middleware [~@(when site? [(ig/ref :duct.middleware.web/webjars)]) ~(ig/ref :duct.middleware.web/defaults) @@ -102,6 +104,7 @@ ~@(when api? [:duct.middleware.web/format {}]) ~@[] ~@(when site? [:duct.middleware.web/webjars {}]) ~@[] + ~@(when site? [:duct.middleware.web/hiccup {}]) ~@[] ~@(->> (route-data-seq routes) (mapcat find-handlers-in-route-data) diff --git a/test/duct/middleware/web_test.clj b/test/duct/middleware/web_test.clj index ca82e6c..a9fbe49 100644 --- a/test/duct/middleware/web_test.clj +++ b/test/duct/middleware/web_test.clj @@ -91,3 +91,21 @@ {:static {:files [(str tempdir)]}}) (is (.exists (.toFile tempdir))) (Files/deleteIfExists tempdir))) + +(deftest test-wrap-hiccup + (is (= {:status 200 + :headers {"Content-Type" "text/html;charset=UTF-8"} + :body "\nfoo"} + ((wrap-hiccup (constantly [:title "foo"])) {}))) + (is (= {:status 200 + :headers {"Content-Type" "text/html;charset=UTF-8"} + :body "\nfoo"} + ((wrap-hiccup (constantly {:body [:title "foo"]})) {}))) + (is (= {:status 201 + :headers {"Content-Type" "text/html;charset=UTF-8"} + :body "\nfoo"} + ((wrap-hiccup (constantly {:status 201, :body [:title "foo"]})) {}))) + (let [response {:status 200 + :headers {"Content-Type" "text/plain;charset=UTF-8"} + :body "Foobar"}] + (is (= response ((wrap-hiccup (constantly response)) {}))))) diff --git a/test/duct/module/web_test.clj b/test/duct/module/web_test.clj index c34bff8..3e7d0c9 100644 --- a/test/duct/module/web_test.clj +++ b/test/duct/module/web_test.clj @@ -101,6 +101,7 @@ (deftest site-module-test (is (= {:duct.router/reitit {:routes [] + :data {:middleware [(ig/ref :duct.middleware.web/hiccup)]} :middleware [(ig/ref :duct.middleware.web/webjars) (ig/ref :duct.middleware.web/defaults) @@ -136,6 +137,7 @@ :handler (ig/ref :duct/router) :logger (ig/refset :duct/logger)} :duct.middleware.web/webjars {} + :duct.middleware.web/hiccup {} :duct.middleware.web/stacktrace {} :duct.handler.static/bad-request {:headers {"Content-Type" "text/html; charset=UTF-8"}