Skip to content

Instantly share code, notes, and snippets.

@tdantas
Last active November 3, 2019 19:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tdantas/1daa70b780d80e51e86416eb7dcf95ac to your computer and use it in GitHub Desktop.
Save tdantas/1daa70b780d80e51e86416eb7dcf95ac to your computer and use it in GitHub Desktop.
Port simple JS function to Clojure ( make it simple to test and isolating side-effects )
/*
Goal:
1. create user database
2. send confirmation email
3. commit or rollback transaction
- 1 and 2 must be somehow transactional
( if sendgrid rejects the email "http response status 400 - 500 range", you must rollback the transaction )
Context:
express handler is calling the UserCreation function passing the http body as argument
(we are assuming here the schema validation was made at handler level )
app.post('/users', function (req, res) {
user = userService.userCreation(req.body) ;
res.send(user)
})
*/
const db = require('./db')
const email = require('./email')
const bugTracker = require('./bugTracker')
/* user schema
{name: 'name',
email: 'user@email.com'
password: 'secret'}
*/
function userCreation(user) {
try {
const tx = db.beginTransaction();
user.password = bcryptPassword(user.password)
const userSaved = db.insert(tx, user);
email.sendConfirmation(userSaved.email);
tx.commit();
} catch (exception) {
tx.rollback();
bugTracker.notify("userCreation", e.message)
throw UserCreationFailed(e.message)
}
}
@tdantas
Copy link
Author

tdantas commented Nov 3, 2019

;; using compojure + components
;; no protocols

  components :db (new-db config), 
             :mail-client (new-client config) 
             :bug-tracker (new-bug-tracker config)
             :routes (new-routes config) depends [:db :mail-client :bug-tracker ] 

compojure handler

routes.clj

(defn mail-executor [client]
  (fn [user]
     (mailer/send-confirmation client user)))

(defn bug-tracker-executor [client]
   (fn [message data]
     (rollbar/notify client message data)))


(defn tx-executor [db]
  (fn [f])
    (jdbc/with-db-transaction [tx {:datasource db}] (f tx)))
    
(defn db-executor [conn query]
  (jdbc/execute! conn query ))


 
(defn app [{:keys [db mail-client bug-tracker]}]
    (let [system {:tx-executor (tx-executor db)
                  :db-executor  db-executor
                  :mail-executor (mail-executor client)
                  :bug-tracker-executor (bug-tracker-executor bug-tracker) }]
      (routes
         (POST "/users" request (user-creation  system (:params request))))

user-service.clj

(defn user-creation-executor [{:keys [tx-executor mail-executor bug-tracker-executor]} user]
   (tx-executor (fn [tx]
                  (let [user (assoc user :password (bcrypt (:password user)))
                        user (db-executor tx (build-sql-insert user)))
                    (mail-executor user))))

(defn user-creation  [{:keys [tx-executor mail-executor bug-tracker-executor]} user]
  (try
     (user-creation-executor system user)
     (catch Exception e 
       (bug-tracker-executor (ex-message e))
       (throw (ex-info "UserCreationFailed" {:type ::user-creation-failed
                                             :reason (ex-message e)
                                             :data (ex-data e)})))))


Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment