Clojure/LISP REST client design

Tag: design , clojure , lisp Author: pwwxp Date: 2013-06-11

Coming from an OOP background, I have a doubt on the recommended way of API design in Clojure. For example in an OOP language(Python here), for using some API I would do this:

api = someWebService()
api.setWriteApiKey(WRITE_API_KEY)
api.sampleloadSong('file.mp3')

In the above example, I set the API key once and call the associated methods again and again without ever passing the API key again. What is the recommended way of doing this in Clojure or any other LISP family of languages ?

Do I need to pass the key in each and every function call like this:

(sampleloadSong "WRITE_API_KEY" "file.mp3")

Or is there any other better approach.

Produce an immutable API object, which you will use further again and again: (make-api "the key" ...) ... (sample-load-song api song). It is actually a quite reasonable design even in imperative languages.
@om-nom-nom Can you explain it with a short example ?

Best Answer

To prevent the repetition problem you describe, you can make a function that returns an api function that remembers the keys, (closes over them)

(defn make-client [key] (partial api key))

Then later in your program:

(let [api-fn (make-client WRITE_API_KEY)]
  (api-fn :sample-song "song.mp3")
  ...
  (api-fn  :delete-song "other-song.mp3"))

Though many people consider it preferable to pass a config map as the first argument to each api call.

 (api {:key WRITE_API_KEY} ....)

There is another common approach where people define the keys as a dynamically bindable symbol and require the callers to bind it appropriately:

(def *api-key* :unset)

(defn api .... use *api-key* )

from caller's namespace:

(binding [*api-key* WRITE_API_KEY]
   (api :add-song "foo.mp3"))

This approach may be less popular than it used to be, and my personal preference it to pass a config map, though that is just my opinion.