Fork me on GitHub
Kira McLean19:12:42

What’s the best to way to list the keys that a map is missing? E.g. with a problem like this for a specced map, what do you guys do to collect those key-names? I’m looking at using spec to validate data in a web app so ultimately I’d like to translate the missing keys into a message like “<key-name> is required” but I’m not sure what’s the best way to get a hold of the names of the missing keys.

{:path [],
  :pred (clojure.core/fn [%] (clojure.core/contains? % :key-name)),
  :via [,,,],
  :in []}

Kira McLean19:12:25

I was looking through expound to try to see how they do it.. it looks like the core of it is, where form is a :pred but I don’t understand how that :expound.spec/contains-key-pred works..

Kira McLean19:12:55

I don’t see how it returns the name of the failed key.. when I try something similar it just returns ::s/invalid, which seems like what I would expect.


@UPGS9BS0L Expound is just parsing the s-expression of the pred. The trick is that expound will take the pred e.g. something like (clojure.core/fn [%] (clojure.core/contains? % :expound.printer/foo)) And then it will throw away the clojure.core/fn [%] part with the (nth form 2) on line 188


Then it uses spec to parse the s-expression to pull out the keyword of the spec


Here’s a little script to show each step. It’s just an example to show how Expound figures out each part of the :pred

(let [first-problem (first (::s/problems (s/explain-data ::some-spec {})))]
     :pred (:pred first-problem)
     :part-of-pred (nth (:pred first-problem)  2)
     :match (s/conform :expound.spec/contains-key-pred (nth (:pred first-problem)  2))
  ;; This returns:
  #_ {:pred (clojure.core/fn [%] (clojure.core/contains? % :expound.printer/foo)),
   :part-of-pred (clojure.core/contains? % :expound.printer/foo),
   :match [:simple {:contains clojure.core/contains?, :arg %, :kw :expound.printer/foo}]}


Does that help?

Kira McLean20:12:26

ah cool, yeah that does make sense. Thank you! So is that how you’d recommend going about getting a hold of those keys? Is there a simpler way to just get spec to tell me which req keys are missing?


@UPGS9BS0L Unfortunately, as of spec1, that’s the way I know of to get the missing keys. Things may change in spec2, but I don’t know of any specific plans for this.


It’d be really nice if spec2 included both the missing key and the fully-qualified key in the case of keys included via :req-un.


(right now if you use :req-un, sometimes Expound will warn <can't find spec for unqualified spec identifier> because it doesn’t know what spec you meant by the kw :foo)

Kira McLean21:12:12

This is really helpful, then. Thanks for all the info!