June 19, 2018

Duct modules for MongoDB and Immutant

Hey that’s me again !

As I’m planning to implement the TechEmpower framework benchmark for the Clojure’s Duct framework I wanted to use MongoDB (because no Clojure framework was using it for this benchmark) from a duct application, and also be able to run it on Immutant because I’ve seen that it was the top performer for both the json and plaintext tests, so why not run duct on top of it?

Well that’s what I did!

duct-mongodb

This library provides two things:

  • a Boundary record that holds both the Monger connection (:conn) and the selected database (:db).
  • a multimethod for :duct.database.mongodb/monger that initiates the connection based on those options into the Boundary.

You can connect to mongo by URI:

{:duct.database.mongodb/monger 
  {:uri "mongodb://127.0.0.1:27017/hello?username=foo&password=bar"}

By host & port:

{:duct.database.mongodb/monger 
  {:host "127.0.0.1", :port 27017, :db-name "hello"}}

And customize the connection options:

{:duct.database.mongodb/monger 
  {:host "127.0.0.1", :port 27017, :db-name "hello"
   :options {:socket-timeout 1234
             :threads-allowed-to-block-for-connection-multiplier 300}}}

Example

Consider a MongoDB database where a users collection exist, containing documents having at least a username field.

The database connection can be extracted from this module Boundary by using the :db key.

If you need access to the whole connection you can do so using the :conn key.

(ns my-project.boundary.user-db
  (:require [duct.database.mongodb.monger]
            [monger.collection :as mc]))
            
(defprotocol UserDatabase
  (get-user [db username]))
  
(extend-protocol UserDatabase
  duct.database.mongodb.monger.Boundary
  (get-user [{:keys [db]} username]
    (mc/find-one-as-map db "users" {:username username})))

You’ll find more information on my Github

duct-immutant

This library adds Integrant methods that dispatch off the :duct.server.http/immutant key, which is derived from :duct.server/http. The corresponding value is a map of options for the Immutant Ring adapter, plus a :handler key that takes a handler function.

For example:

{:duct.server.http/immutant
 {:port    3000
  :handler (fn [request]
             {:status  200
              :headers {"Content-Type" "text/plain"}
              :body    "Hello World"})}}

A :logger key may also be specified, which will be used to log when the server starts and when it stops. The value of the key should be an implementation of the duct.logger/Logger protocol from the duct.logger library

You’ll find more information on my Github

Alexandre Grison - //grison.me - @algrison