Proof of concept for bringing your own JSON library#53
Proof of concept for bringing your own JSON library#53rome-user wants to merge 1 commit intognarroway:masterfrom
Conversation
|
The PR uses multimethods and a dynamic var to select the desired JSON implementation. I haven't looked into it too much but it feels that a better alternative would be to add |
|
I've changed my mind on my idea but never noted it here. I think in general "choosing your own JSON library" is anti-modular. If there are two libraries that depend on |
|
I'd say libraries that use Hato should provide their users an ability to specify a custom Hato client. It makes sense regardless of JSON processing. Multiple JSON codecs in a Clojure project can be easily achieved with my approach - you can simply construct multiple Hato clients. A Hato client is not inherently a singleton, you specify it per-request. In fact, by default Hato builds a new client for each request. |
|
There is a rather neat little trick that (def from-string
(or
(find-impl "cheshire" :from/string) ;; cheshire.core/parse-string
(find-impl "data.json" :from/string) ;; clojure.data.json/read-str
(find-impl "jsonista" :from/string) ;; jsonista.core/read-value
(no-lib-found!)))
(def from-stream
(or
(find-impl "cheshire" :from/stream) ;; cheshire.core/parse-stream
(find-impl "data.json" :from/stream) ;; clojure.data.json/read
(find-impl "jsonista" :from/stream) ;; jsonista.core/read-value
(no-lib-found!)))
(def to-string
(or
(find-impl "cheshire" :to/string) ;; cheshire.core/generate-string
(find-impl "data.json" :to/string) ;; clojure.data.json/write-str
(find-impl "jsonista" :to/string) ;; jsonista.core/write-value-as-string
(no-lib-found!)))
(def to-stream
(or
(find-impl "cheshire" :to/stream) ;; cheshire.core/generate-stream
(find-impl "data.json" :to/stream) ;; clojure.data.json/write
(find-impl "jsonista" :to/stream) ;; jsonista.core/write-value
(no-lib-found!)))With (defn- try-resolve [sym]
(try @(requiring-resolve sym)
(catch Exception _ nil)))
(defn- find-impl
[lib direction]
(case lib
"cheshire"
(case direction
:from/string (try-resolve 'cheshire.core/parse-string)
:from/stream (try-resolve 'cheshire.core/parse-stream)
:to/string (try-resolve 'cheshire.core/generate-string)
:to/stream (try-resolve 'cheshire.core/generate-stream))
"data.json"
(case direction
:from/string (try-resolve 'clojure.data.json/read-str)
:from/stream (try-resolve 'clojure.data.json/read)
:to/string (try-resolve 'clojure.data.json/write-str)
:to/stream (try-resolve 'clojure.data.json/write))
"jsonista"
(case direction
:from/string (try-resolve 'jsonista.core/read-value)
:from/stream (try-resolve 'jsonista.core/read-value)
:to/string (try-resolve 'jsonista.core/write-value-as-string)
:to/stream (try-resolve 'jsonista.core/write-value))
))
(defn- no-lib-found! []
(throw
(IllegalStateException.
"None of`cheshire`, `data.json`, or `jsonista` could be found on the classpath!")))Hope this helps... |
|
@p-himik I agree that being able to provide your own encode/decode functions when building the client, is in many ways the cleanest & most flexible approach. However, it doesn't really help with dropping the [EDIT] - apologies, it seems that hato does NOT depend on
|
Addresses #52.
This is not ready to be merged; unit test are not written yet. Here is an example of how to use:
(require 'hato.optional.data-json).The current design introduces a dynamic variable
hato.middleware/*json-lib*, which gets set when you load the optional JSON adapter, or you can bind it yourself!