I have read that s/keys only supports keywords. I have a large external json message for which i would to perform some top-level schema validation. Rather than performing a keywordize-keys, which may descend past the desired schema and into embedded content, I was hoping to keep the message keys as strings and use validation upon them. From what i can see, this would be done similar to this:
(def last-name? #(= "last" %))
(def first-name? #(= "first" %))
(def age? #(= "age" %))
(spec/def ::last-name (spec/tuple last-name? string?))
(spec/def ::first-name (spec/tuple first-name? string?))
(spec/def ::age (spec/tuple age? (spec/and pos-int? int?)))
(spec/def
::who
(spec/coll-of
(spec/or :last ::last-name :first ::first-name :age ::age)
:kind map?
:count 3
:distinct true))
(spec/explain ::who {"last" "smith" "first" "bob" "age" 10})
Is this the recommended path when using map keys which are strings, not keywords?This approach should work, you can simplify those preds using sets though, like #{“first”} (and at that point I would just inline them into ::first-name etc
You also might find it useful to wrap s/nonconforming around the s/or to simplify the conformed structure
can you provide a case where s/conform who json-map would return something undesirable, where s/nonconforming would be wanted?
(spec/or :last ::last-name :first ::first-name :age ::age) is going to conform to [:last ["last" "smith"]]
(spec/nonconforming (spec/or :last ::last-name :first ::first-name :age ::age)) will conform to ["last" "smith"]
if you use :into {} in your who spec, you can actually conform back to the original map if you want that
great to know. appreciated
didn't need the :into. wrapping the s/or in a nonconforming was enough to return a map when calling conform