@@ -1523,6 +1523,93 @@ used in this example for the sake of brevity.
1523
1523
Now that we have both a server and client, we can `(reset)` the REPL
1524
1524
and check the web application at: <http://localhost:3000>
1525
1525
1526
+ == Existing Applications
1527
+
1528
+ So far we have worked on the assumption that you are building a Duct
1529
+ application from scratch, but what if you have an existing application?
1530
+ Can Duct provide any benefit in that case?
1531
+
1532
+ If you use Integrant, you can use parts of Duct. This section will cover
1533
+ common use-cases.
1534
+
1535
+ === Integrant '`main`' replacement
1536
+
1537
+ A common pattern for using Integrant have a `-main` function that loads
1538
+ and initiates an Integrant configuration. In many cases, you can use
1539
+ Duct to replace this with a data-driven approach.
1540
+
1541
+ For example, suppose you've written an application with a custom server
1542
+ and worker queue component. You may have an Integrant configuration file
1543
+ that looks like this:
1544
+
1545
+ .resources/example/app/config.edn
1546
+ [,clojure]
1547
+ ----
1548
+ {:example.app/server
1549
+ {:queue #ig/ref :example.app/worker-queue}
1550
+
1551
+ :example.app/worker-queue
1552
+ {:worker-threads 32}}
1553
+ ----
1554
+
1555
+ In order to run this configuration, you have a main function that loads
1556
+ in the config file and populates the it with additional values from the
1557
+ environment. In the example below, the server port number is pulled from
1558
+ the `PORT` environment variable.
1559
+
1560
+ .src/example/app/main.clj
1561
+ [,clojure]
1562
+ ----
1563
+ (ns example.app.main
1564
+ (:require [clojure.java.io :as io]
1565
+ [integrant.core :as ig]))
1566
+
1567
+ (defn -main [& _args]
1568
+ (let [port (some-> (System/getenv "PORT")
1569
+ (Integer/parseInt)
1570
+ (or 3000))
1571
+ config (-> (io/resource "example/app/config.edn")
1572
+ (slurp)
1573
+ (ig/read-string)
1574
+ (assoc-in [:example.app/server :port] port))]
1575
+ (ig/load-namespaces config)
1576
+ (ig/init config)))
1577
+ ----
1578
+
1579
+ Duct can be used to replace all this with a data-driven configuration.
1580
+ In your `deps.edn` file, add a Duct alias:
1581
+
1582
+ .deps.edn
1583
+ [,clojure]
1584
+ ----
1585
+ {:aliases
1586
+ {:duct {:extra-deps {org.duct-framework/main {:mvn/version "0.1.11"}}
1587
+ :main-opts ["-m" "duct.main"]}
1588
+ ;; rest of your deps.edn
1589
+ }}
1590
+ ----
1591
+
1592
+ Then move your configuration into `duct.edn` under the `:system` key.
1593
+ Use the `:vars` key to define the options you want to pull from the
1594
+ environment or from command-line options.
1595
+
1596
+ .duct.edn
1597
+ [,clojure]
1598
+ ----
1599
+ {:vars
1600
+ {port {:env PORT, :type :int, :default 3000}
1601
+ :system
1602
+ {:example.app/server
1603
+ {:port #ig/var port
1604
+ :queue #ig/ref :example.app/worker-queue}
1605
+
1606
+ :example.app/worker-queue
1607
+ {:worker-threads 32}}}
1608
+ ----
1609
+
1610
+ To run your application, use `clojure -M:duct`, or the `duct` alias
1611
+ defined in the <<Project Setup>> section.
1612
+
1526
1613
== Integrations
1527
1614
1528
1615
=== Docker
0 commit comments