In essence, the Configuration principle of the 12 Factor-Application Pattern states that an application's configuration and an application's code should be completely independent of each other. Our hipstr application currently violates this principle in a key area: the database connection. This, however, is easily resolved.
For our development server, we will create profiles.clj
and have the lein-env
plugin generate the .lein-env
file. Currently, our hipstr.models.connection/db-spec
expects 5 settings: :classname
, :subprotocol
, :subname
, :user
, and :password
.
Theoretically, we could transfer the entire db-spec
map into the profiles.clj
file, such as shown below:
{:dev {:env {:db-spec {:classname "org.postgresql.Driver" :subprotocol "postgresql" :subname "//localhost/postgres" :user "hipstr" :password "p455w0rd})
We could then modify hipstr.models.connection/db-spec
to just the following:
(ns hipstr.models.connection (:require [environ.core :refer [env]])) (def db-spec (env :db-spec))
However, this would prove to be our fall from grace during deployment outside the development server, because environ
does not support embedded configuration maps for environment variables or Java system properties. As such, we need to flatten our settings. So do the following steps:
profiles.clj
file alongside our project.clj
file in the hipstr project folder.{:dev {:env {:dev? true :db-classname "org.postgresql.Driver" :db-subprotocol "postgresql" :db-subname "//localhost/postgres" :db-user "hipstr" :db-password "p455w0rd"}}}
The next time you run lein ring server
, the .lein-env
file will be generated and the above profiles.clj
map will be included, thus allowing environ
to find the settings when called upon.
Next, we need to modify our hipstr.models.connection
namespace to make use of the environ
library:
hipstr.models.connection
namespace to include environ
:(ns hipstr.models.connection (:require [environ.core :refer [env]]))
environ
equivalent:(def db-spec {:classname (env :db-classname) :subprotocol (env :db-subprotocol) :subname (env :db-subname) :user (env :db-user) :password (env :db-password)})
That's all we have to do! Our database connection can now read configuration from anywhere environ
resolves the key!
Before we restart our development server however, let's adjust the migratus-config
in the hipstr.handler
namespace. In the hipstr.handler
namespace, perform the following steps:
hipstr.models.connection/db-spec
in the :require
:(ns hipstr.handler (:require [compojure.core :refer [defroutes]] [hipstr.models.connection :refer [db-spec]] ...)
:db map
in our migratus-config
, and instead use the referred db-spec
:(def migratus-config
{:store :database
:migration-dir "migrations"
:migration-table-name "_migrations"
:db db-spec})
That's it! All of our database references are now using an external configuration. Restart your development server and create a new user, and you'll find that everything behaves the same way.
3.17.79.206