Hey!
I’ve ran into (obvious) issue when building JSON REST API with Liberator for my app. Main configuration is just nested structure of Clojure data (EDN) stored in file. Goal of the REST API is to expose fragments of this data to user (as Liberator resource
), and update it with user-provided version via PUT
. Easy peasy, right?
Nope. My configuration structure is not JSON! All (important) information about data type (set, hash-map, keyword, etc) is lost.
See this example:
(s/def ::name string?)
(s/def ::kind #{:dog :cat :mice})
(s/def ::friends (s/coll-of ::name :kind set?))
(s/def ::entity (s/keys :req-un [::name ::kind ::friends]))
(s/def ::entities (s/coll-of ::entity))
(def entities
[{:name "Spike"
:kind :dog
:friends #{"Jerry"}}
{:name "Tom"
:kind :cat
:friends #{"Jerry"}}
{:name "Jerry"
:kind :mice
:friends #{"Tom" "Spike"}}])
(spec/valid? ::entities entities) ;; => true
(json/encode entities) ;; => "[{\"name\":\"Spike\",\"kind\":\"dog\",\"friends\":[\"Jerry\"]},{\"name\":\"Tom\",\"kind\":\"cat\",\"friends\":[\"Jerry\"]},{\"name\":\"Jerry\",\"kind\":\"mice\",\"friends\":[\"Tom\",\"Spike\"]}]"
(json/decode (json/encode entities)) ;; => ({"name" "Spike", "kind" "dog", "friends" ["Jerry"]} {"name" "Tom", "kind" "cat", "friends" ["Jerry"]} {"name" "Jerry", "kind" "mice", "friends" ["Tom" "Spike"]})
(spec/valid? ::entities (json/decode (json/encode entities))) ;; =>false
Information about all non-JSON data types is lost during conversion.
This seems like impossible case but wait - there’s spec
with all the information about valid data types specified. If only I can somehow coerce
into this spec
…
I don’t know if Liberator
in original application is important - it’s doing JSON conversion implicitly, but in my opinion eventual solution will be independent of Liberator - but mentioning it, just in case.
Do you have any ideas how to deal with it?
Slawek