ring-swagger 2019-03-19

It’s that time of year again, so I’m playing with compojure-api 🙂

And I have this route:

(GET "/" {system :system :as request}
      :coercion :spec 
      :summary "Returns all the things"
      :return (spec-tools/merge ::specs/identifiable
                                ::specs/named
                                (spec/keys :opt-un [::specs/description]))
      [])

Which shows up in the swagger ui, which is great, but it doesn’t show anything useful in for the return value, it only shows {}

If I change to

(GET "/" {system :system :as request}
      :coercion :spec 
      :summary "Returns all the things"
      :return (spec/merge ::specs/identifiable
                   	  ::specs/named
                                (spec/keys :opt-un [::specs/description]))
      [])

I get

{
  "_id": "string",
  "name": "string",
  "description": "string"
}

as expected.

You can run the transformation from repl, something like:

(require '[spec-tools.swagger.core :as swagger])
(swagger/transform (spec-tools/merge ::specs/identifiable
                                ::specs/named
                                (spec/keys :opt-un [::specs/description])))

… to see what pops up.

ardoq.api.crud-api-v2> (swagger/transform (spec/merge ::specs/identifiable
                                ::specs/named
                                (spec/keys :opt-un [::specs/description])))

;; => {:type "object",
 :properties
 {"_id"
  {:type "string",
   :x-allOf [{:type "string"} {}],
   :title "ardoq.specs/_id"},
  "name" {:type "string"},
  "description" {:type "string", :x-nullable true}},
 :required ["_id" "name"]}
ardoq.api.crud-api-v2> (swagger/transform (spec-tools/merge ::specs/identifiable
                                ::specs/named
                                (spec/keys :opt-un [::specs/description])))
;; => {}
ardoq.api.crud-api-v2> 

and somewhat involved, IIRC 🙂

now that you know it’s not working properly, would you have time to make a PR? 😉

I have time to make an issue, but I don’t know if I’m capable of creating a PR.

Issue is good, I should have time to check if that’s a small fix or needs more time. most likely just missing a multimethod dispatch for that.

but now just now (the time)

user> (defmethod swagger/accept-spec 'spec-tools.core/merge [_ _ children _]
  ;; Use x-anyOf and x-allOf instead of normal versions
  {:type "object"
   :properties (->> (concat children
                            (mapcat :x-anyOf children)
                            (mapcat :x-allOf children))
                    (map :properties)
                    (reduce merge {}))
   ;; Don't include top schema from s/or.
   :required (->> (concat (remove :x-anyOf children)
                          (mapcat :x-allOf children))
                  (map :required)
                  (reduce into (sorted-set))
                  (into []))})
;; => #multifn[accept-spec 0x3f8c13a8]
user> (swagger/transform (spec-tools/merge ::has-string ::has-int))
;; => {:type "object", :properties {}, :required []}
user> 

Closer, but still no cigar 🙂

you have mad skills at extending libraries 🙂

children is nil for spec-tools.core/merge

you need to check also from the visitor ns that there is a mm dispatch to walk the childs.

it goes: 1) visitor walks the specs (need an mm for all form symbols) 2) json-schema is used as a base transfromation 3) swagger overrides the stuff that it can’t handle

user> (swagger/transform (spec-tools/merge ::has-string ::has-int))
;; => {:type "object",
 :properties
 {"string" {:type "string"},
  "int" {:type "integer", :format "int64"}},
 :required ["int" "string"]}
user> 

I might just have time to make a pr after all 🙂

awesome! 🙂

seems to be the same case for spec/coll-of

@daveliepmann has joined the channel

I’ve got another sort of weird case:

(POST "/" {{document :json-params} :params
               system :system :as request}
      :coercion :no-coercion
      :summary "Create one thing"
      :body [document spec]
      :return  (spec/merge spec ::specs/metadata)
      (create* (service-kw system) (request-util/->context request) spec document)))))

only returns the first of the merged specs. It works as expected if :return only contains spec (which is also a result of a merged spec)

I’ll be happy to file an issue for this if it’s supposed to be supported like this.