Skip to content

ferdinand-beyer/init

Repository files navigation

init

Build Status cljdoc Clojars

Init is a small Clojure framework for application initialization and dependency injection. It is heavily inspired by Integrant and similar to Component, but also draws ideas from popular Java projects like Dagger 2, Guice, Spring and CDI.

Status: Alpha. The concepts should be pretty stable, but API details might still change.

Rationale

I developed Init because I was unhappy with available solutions in Clojure.

  • Component relies on records and protocols, and has some constraints on what can have dependencies.
  • Mount encourages global state with hidden dependencies, and does not support dependency inversion at all.
  • Integrant separates configuration from implementation, which sounds like a good idea at first, but adds complexity in practice.

Init borrows many ideas from Integrant, such as configuration as data, keys that support hierarchy, and system maps, while offering an alternative to derive configuration from code via metadata.

In the Java community, there has been a clear transition from file based configuration (like early Spring's XML configuration) towards annotation-based configuration, directly in code. Init suggests that this has proven useful, and offers a similar programming experience to Clojure programmers.

Usage

Init allows you to define components and their dependencies using Metadata on vars, and provides a mini-language to customize injected values:

(defn read-config
  {:init/name ::config}
  []
  (edn/read-string (slurp "config.edn")))

(defn database
  {:init/inject [[:get ::config :db-uri]]}
  [uri]
  (db/connect uri))

(defn handler
  {:init/inject [:into-first {:db ::database}]}
  [{:keys [db] :as request}]
  (resp/response (query-status db)))

(defn start-server
  {:init/inject [::handler [:get ::config :port]]}
  [handler port]
  (jetty/run-jetty handler {:port port}))

(defn -main []
  (-> (discovery/from-namespaces [*ns*])
      (init/start)
      (init/stop-on-shutdown)))

While configuration via metadata is preferred and distinguishes Init from other solutions, it is completely optional. Init has a modular design, and allows you to mix and match different approaches for configuration, discovery and component lifecycle.

Have a look at Init's design to find out more.

Installation

Releases are available from Clojars.

deps.edn:

com.fbeyer/init {:mvn/version "0.2.96"}

Leiningen/Boot:

[com.fbeyer/init "0.2.96"]

Documentation

License

Distributed under the MIT License.
Copyright © 2022 Ferdinand Beyer