Multimethods
You could define the abstraction with multimethods:
1 (ns stadig.storage.methods
2 (:refer-clojure :exclude [get]))
3
4 (defmulti get :backend)
5 (defmulti put :backend)
6 (defmulti delete :backend)
7 (defmulti close :backend)
Implemented them for each backend:
1 (ns stadig.storage.s3
2 (:require
3 [aws.sdk.s3 :as s3]
4 [stadig.storage.methods :as methods]))
5
6 (defmethod methods/get :s3
7 [this bucket key]
8 (when-not bucket
9 (throw (ex-info "Expected bucket" {:type ::bucket-error})))
10 (s3/get-object this bucket key))
11
12 (defmethod methods/put :s3
13 [this bucket key value]
14 (when-not bucket
15 (throw (ex-info "Expected bucket" {:type ::bucket-error})))
16 (s3/put-object this bucket key value)...