Using integrant components in handlers
Using pure API handlers is very cool but sometimes we still need to get our hands dirty by accessing the raw components like:
- The stripe API client
- The datomic connection instance
- The email client
or any others you will define in your SaaS product. For this scenario, we have wrap-inject-system.
wrap-inject-system takes the system and constituent components defined for the :handler/reitit integrant component and injects it into the final handler.
Usage
Let's say that in system.edn you have :handler/reitit defined like this:
:handler/reitit {:conn #ig/ref :db.datomic/connection
:email-client #ig/ref :services/email
:powerpack #ig/ref :powerpack/app
:env #ig/ref :system/env}
In the reitit routes you can define a new handler like so
(ns saas.web.reitit-handler
(:require
...
[saas.web.middleware.core :as mw])
(def routes
[...
["/my-super-impure-handler"
{:post {;; Add the middleware to this handler
:middleware [::mw/inject-system]
:summary "This handler will do impure things"
;; Notice the second argument `system` for the handler
:handler (fn [req {:keys [email-client conn] :as system}]
(email/send-email email-client (my-cool-email))
(let [db (d/db conn)]
(get-user db ...)))}}]
]))
Using the ::mw/inject-system middleware, you can have handlers that take 2 arguments: (i) the actual request (ii) the system map defined in system.edn for the reitit handler.
When to use it
Use this middleware and style of handlers when you need to access your system into your handlers and the logic is either highly sequential or parallel that you cannot use nexus. This is an elegant way of including the system in your handlers without higher order functions or appending dependencies on the request map itself.
Traditionally you would've implemented higher order functions like this:
(defn make-my-impure-handler
[system]
(fn [req]
...))
;; and then in the router
[["/my-handler" {:post {:handler (make-my-impure-handler system)}}]]
This works well enough but I find the version written through ::mw/inject-system to be easier to test and follow.