Search code examples
clojureclojure.spec

Clojure.spec "or" equivalent of "s/and"


I've enjoyed working with clojure.spec; it has helped uncover data errors closer to the cause. Currently I am using it to validate a response to a web server request, but I am having difficulty with the syntax for the clojure.spec operation that would allow two different map structure responses.

In my data, there are two possible responses from the web server request:

{:assignment "1232123"} and

{:no-more-assignments true}

I could use multi-spec, but that seems verbose for something that could be as simple as having one spec for each case and defining the spec as:

(s/def ::response
  (s/or ::case-1 ::case-2))

Is there some syntax that I am overlooking or will I need to use multi-spec?


Solution

  • You can use or and and with keys specs:

    (s/def ::assignment string?)
    (s/def ::no-more-assignments boolean?)
    (s/def ::response
      (s/keys :req-un [(or ::assignment ::no-more-assignments)]))
    
    (s/explain ::response {:assignment "123"})
    ;; Success!
    (s/explain ::response {:foo true})
    ;; val: {:foo true} fails spec: :sandbox.so/response predicate: (or (contains? % :assignment) (contains? % :no-more-assignments))