Fork me on GitHub

Hello, please forgive me as I'm a bit of a noob with swagger and spec but I'm having a little trouble with the swagger api with spec coercion. Basically I have some maps where the fields have quite complicated specs and test generators, here is an example contract map with a couple of specific decimal fields:

(defn non-negative? [n] (>= n 0))
(defn pos-scaled-decimal?
    (fn [x]
      (and (non-negative? x) (decimal? x) (>= scale (.scale x))))
    :gen #(gen/fmap (fn [x] (bigdec (/ (Math/abs x)
                                      (Math/pow 10 (+ 1 (rand-int 6))))))

(s/def ::pos-decimal-2dp (pos-scaled-decimal? 2))
(s/def ::urate1 ::pos-decimal-2dp)
(s/def ::urate2 ::pos-decimal-2dp)
(s/def ::contract (s/keys :req-un [::urate1 ::urate2]))
I would like to use generated maps as example input data on the swagger UI, on a vanilla swagger install to fill out the example post body with generated data I think that would look something like this:
:swagger {:paths {"/contract" {:post {:requestBody {:content {:application/json {:schema {:type "object" :example (gen/generate (s/gen ::contract))}}}}}}}
Is there a way to do this with reitit? I tried to use the ::contract spec with parameter coercion:
        {:post {:handler    (fn [_]
                              {:status 200
                               :body   "?"})
                :parameters {:body ::contract}}}]
But example data on swagger ui gets turned into {:urate1 {}, :urate2 {}} not (for example) {:urate1 0.01M, :urate2 0.07M} Thanks


@billh you can wrap the spec into spec-tools.core/Spec, which can have extra metadata, including the :example, something like:

(st/spec {:spec ::contract
          :swagger/example (-> (s/exercise ::contract 1) first second)})
, should be picked up by the swagger transformer


also, both the coercion and the swagger transformer need to know the type of the leaf predicates to work properly. In your example the pos-scaled-decimal? should return a spec-tools.core/Spec too, instead of just functions / reified clojure.spec protocols.


something like this could work:

(defn pos-scaled-decimal?
    {:type :double
     :spec (s/spec
             (fn [x]
               (and (non-negative? x) (decimal? x) (>= scale (.scale x))))
             :gen #(gen/fmap (fn [x] (bigdec (/ (Math/abs x)
                                                (Math/pow 10 (+ 1 (rand-int 6))))))


or use s/and and have the type as first argument:

(s/def ::urate1 (s/and integer? ::pos-decimal-2dp))


types are inferred from most/all core predicates.


Working now, thanks Tommi. Thanks for the great work you're doing on reitit as well!