duct

branch14 2025-05-02T07:52:00.132279Z

For larger blobs of text (like documentation) I would like to store those in separate files and merge them into the duct config, rather than having all in duct.edn. Integrant's expand-key comes to mind. In case of reitit routes I need to "merge" into a list. I can pass :duct.module/web into my module and manipulate the routes myself. Is this the way to go? Or are there better options?

branch14 2025-05-02T14:02:05.241519Z

I went down this path and ended up in circular dependencies. I guess there must be a better way.

weavejester 2025-05-02T16:03:20.009009Z

Which version of Duct are you using? The current stable version that uses Leiningen, or the upcoming version that's its own tool?

branch14 2025-05-02T16:17:27.552379Z

Bleeding edge. :) Sorry, I missed to mention that.

weavejester 2025-05-02T16:20:31.234319Z

Can you tell me a little more about the blobs of text?

weavejester 2025-05-02T16:26:22.908129Z

Like, are there lots of little strings of text that might benefit from being in a single mapping file, or are there relatively few but long pieces of text, which might be best put in separate files?

branch14 2025-05-02T18:19:12.573699Z

Think of extensive documentation that is displayed in a Swagger UI to document an API. The more general question is: How can I use a duct module, specifically expand-key to manipulate the initial configuration provided by duct.edn.

weavejester 2025-05-02T20:28:43.302299Z

So the expand-key method returns some map that is then merged into the outer configuration map. There's more documentation on it in the Integrant README, but essentially you might have a configuration:

{:your.module/example {}}
And then an expand-key defined as:
(defmethod ig/expand-key :your.module/example
  [_ _options]
  {:some/a {}, :some/b {}})
Then this would expand out to create a configuration:
{:some/a {}
 :some/b {}}

weavejester 2025-05-02T20:31:56.546549Z

You could also supply a resource or file path to the documentation. I've been planning on adding a #duct/import "filepath" reader tag to facilitate this, but I've yet to fully decide on the specifics.

weavejester 2025-05-02T20:33:36.424589Z

Like it might be useful to allow something like #duct/import ["extra.edn" :inner :key] .

weavejester 2025-05-02T20:33:57.595129Z

To export some key inside a map.

branch14 2025-05-02T21:25:16.094469Z

I created a simple module to read the additional files. But in order to merge them into the reitit routes I also gave it :duct.module/web as a dependency, in order to augment what was already in duct.edn . This created a "Circular dependency between :duct.module/web and :duct.module/web" presumably because my module also provides :duct.module/web .

;; in myapp/duct.clj
(defmethod ig/expand-key ::config [_ {:keys [paths web]}]
  (let [input (fsdb/ingest paths)]
    ;; TODO: merge input into web
    {:duct.module/web web}))

;; in duct.edn
:myapp.duct/config {:paths ["duct"]
                    :web #ig/ref :duct.module/web}

weavejester 2025-05-02T22:00:17.964779Z

Yes, that won't work. References are applied after expansions take place, in a similar way to how macros don't have access to variables - they just see them as symbols. Would a #duct/import reader key solve your particular use-case?

weavejester 2025-05-02T22:00:47.275859Z

i.e. one that can read data from a separate file?

weavejester 2025-05-02T22:01:49.326399Z

Alternatively, you could still use a module, but rather than altering the module directly, you add keys to the router that the module spits out.

weavejester 2025-05-02T22:02:50.142469Z

So you'd merge the extra data into :duct.router/reitit . As long as your module and the Duct web module hit different keys, that should be fine.

branch14 2025-05-07T08:41:25.747279Z

After exploring the 2nd options I must say I'm quite happy with the solution. Thanks for the advice. That said, I think #duct/import would also be useful, in other cases.

branch14 2025-05-03T07:00:27.182699Z

Yes, I guess that would work. And it would make it more obvious where things come from. On the downside of a bit more to type.