Guides

HTML & Integrant

Compose a UI system with Integrant and render Hiccup.

Separate data, views and lifecycle

A Hiccup value describes HTML as vectors: [:h1 "Hello"] is a heading, and [:a {:href "/"} "Home"] is a link with attributes. replicant.string/render renders that data into a response body. Rendering a page does not start a server.

Integrant constructs components from a map and explicit ig/ref dependencies. Fast-Twitch still sees ordinary handler functions and route vectors. You can use Hiccup without Integrant, and neither requires a new routing abstraction.

A complete Ring application graph

(ns application.html
  (:require [integrant.core :as ig]
            [replicant.string :as html]
            [fast-twitch.routing :as routing]))

(defmethod ig/init-key ::settings [_ settings] settings)

(defmethod ig/init-key ::pages [_ {:keys [settings]}]
  {:home (fn [_]
           {:status 200 :headers {"content-type" "text/html; charset=utf-8"}
            :body (str "<!doctype html>"
                       (html/render
                         [:html {:lang "en"}
                          [:head [:meta {:charset "utf-8"}]
                           [:title (:title settings)]]
                          [:body [:h1 (:title settings)]
                           [:a {:href "/hello/Ada"} "Greet Ada"]]]))})
   :hello (fn [{:keys [path-params]}]
            {:status 200 :headers {"content-type" "text/html; charset=utf-8"}
             :body (html/render [:h1 (str "Hello " (:name path-params))])})})

(defmethod ig/init-key ::app [_ {:keys [pages]}]
  (routing/routes
    [{:pattern "/" :method :get :handler (:home pages)}
     {:pattern "/hello/:name" :method :get :handler (:hello pages)}]
    (fn [_] (routing/not-found "Missing"))))

(def config
  {::settings {:title "My application"}
   ::pages {:settings (ig/ref ::settings)}
   ::app {:pages (ig/ref ::pages)}})

(def system (ig/init config))
(def fetch-handler
  (routing/ft-handler (::app system) {:protocol "HTTP/1.1" :remote-addr "unknown"}))

This constructs the Fetch handler; start it through routing/start-server! or use the complete runnable project, which includes dependencies, compiler configuration, tasks, views and startup code.

Read the graph in dependency order

ig/init first initializes settings, then passes that value to pages, then passes those handlers to app. The settings ref becomes the initialized value, not a lookup that each request performs. The page functions close over that component's settings. Routes remain visible together in the application component.

A response body is the rendered string, not the Hiccup vector. Set an HTML content type explicitly. Put user text in Hiccup text nodes so the renderer handles text escaping; concatenating untrusted strings into raw HTML has different semantics. Rendering is not validation of a route parameter's business meaning.

Own resources explicitly

If a component opens a database, socket or watcher, give it an ig/halt-key! method that releases that resource. Call ig/halt! on the initialized system at shutdown. Components containing only pure handler functions do not need invented lifecycle state. A server listener has its own shutdown operation; halt ordering should stop dependants before releasing resources they use.

What to change next

Add a page function, add one visible route pointing at it, and request that route. Add a setting to ::settings and use it in the view. Add middleware around routing/routes in ::app if parsed form data is needed. Form project · Upload project.

Source revision a4eb73f96836d034c7a24fe09dc7d51e4c581f64

Built with Fast-Twitch · Integrant · Datastar

Search documentation

Search pages and API symbols

Start hereWelcome to Fast-TwitchRing HTTP applications and configured native clients and transports in ClojureScript.Start hereGetting startedCompile and run your first Fast-Twitch server.Core conceptsRequest & responseUnderstand the maps at the center of a Fast-Twitch application.Core conceptsRoutingMatch URL patterns and compose handlers.Core conceptsMiddlewareWrap handlers with focused request and response behavior.GuidesHTML & IntegrantCompose a UI system with Integrant and render Hiccup.