Setup a new duct site

Why Duct? Well it’s a great starting point using most of what I want. Compojure, Ring, Component, ClojureScript, 12 Factor methodology.

lein new duct nspkt.ui +cljs +example +heroku +site
cd nspkt.ui && lein setup

Ok, we need some other stuff, like MongoDB, a css framework (Foundation), and authentication.

MongoDB Setup

I like Monger, so let’s add that. In project.clj, add the dependency.

[com.novemberain/monger "3.0.2"]

We need to add a connection string to the env for monger. This took a minute to figure out.

In the project.clj file, under :profiles > :project/dev > :env, add :url. This will write the values to .lein-env.

{:port "3000", :url "mongodb://localhost:27017/nspkt"}

Then we need to update the config.clj to grap the value. Like so.

(def environ
  {
   :http {:port (some-> env :port Integer.)}
   :db {:url (some-> env :url)}
   })

And add a compontent for System.

(ns nspkt.ui.component.mongodb
  (:require [com.stuartsierra.component :as component]
            [monger.core :as mg]
            )
  )

(defrecord MongoDb [url]
  component/Lifecycle
  (start [this]
    (let [{:keys [conn db]} (mg/connect-via-uri (:url this))]
      (assoc this :conn conn :db db)
      )
    )

  (stop [this]
    (if-let [conn (:conn this)]
      (do
        (mg/disconnect conn)
        (dissoc this :conn :db)
        )
      this
      )
    )
  )

(defn db-component [options]
  (map->MongoDb options)
  )

Next add the component to the system, add have the example endpoint depend on it. Don’t forget to add to the :requires. In system.clj.

...
(-> (component/system-map
     :app  (handler-component (:app config))
     :http (jetty-server (:http config))
     :db   (db-component (:db config))
     :example (endpoint-component example-endpoint))
    (component/system-using
     {:http [:app]
      :app  [:example]
      :example [:db]}))
...

And using the component in the example endpoint, endpoint/example.clj.

(ns nspkt.ui.endpoint.example
  (:require [compojure.core :refer :all]
            [monger.collection :as mc]
            [clojure.java.io :as io]))

(defn example-endpoint [{:keys [db] :as config}]
  (context "/example" []
    (GET "/" []
      (prn-str 
        (mc/find-maps (-> db :db) "reports")
        )
      )))

Great! Let’s make sure everything is working. We need to lein deps and start the REPL again.

If you run into trouble it’s some times easier to see what’s going by lein runing.

I added a test record in MongoDB just to see everything works.

It’s not pretty, but it’s pulling stuff out of the DB! Now let’s add a CSS framework to help thing look a little better.