-
Notifications
You must be signed in to change notification settings - Fork 27
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Proof of concept for bringing your own JSON library #53
base: master
Are you sure you want to change the base?
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!