diff --git a/modules/reitit-malli/src/reitit/coercion/malli.cljc b/modules/reitit-malli/src/reitit/coercion/malli.cljc index 311660f7..89dce54c 100644 --- a/modules/reitit-malli/src/reitit/coercion/malli.cljc +++ b/modules/reitit-malli/src/reitit/coercion/malli.cljc @@ -76,33 +76,6 @@ (assoc error :transformed transformed)))) value)))))))) -;; -;; swagger -;; - -(defmulti extract-parameter (fn [in _ _] in)) - -(defmethod extract-parameter :body [_ schema options] - (let [swagger-schema (swagger/transform schema (merge options {:in :body, :type :parameter}))] - [{:in "body" - :name (:title swagger-schema "body") - :description (:description swagger-schema "") - :required (not= :maybe (m/type schema)) - :schema swagger-schema}])) - -(defmethod extract-parameter :default [in schema options] - (let [{:keys [properties required]} (swagger/transform schema (merge options {:in in, :type :parameter}))] - (mapv - (fn [[k {:keys [type] :as schema}]] - (merge - {:in (name in) - :name k - :description (:description schema "") - :type type - :required (contains? (set required) k)} - schema)) - properties))) - ;; ;; public api ;; @@ -156,25 +129,24 @@ {:type specification, :coercion :malli})))) (-get-apidocs [this specification {:keys [parameters responses] :as data}] (case specification - :swagger (merge - (if parameters - {:parameters - (->> (for [[in schema] parameters - parameter (extract-parameter in schema options)] - parameter) - (into []))}) - (if responses - {:responses - (into - (empty responses) - (for [[status response] responses] - [status (as-> response $ - (set/rename-keys $ {:body :schema}) - (dissoc $ :content) - (update $ :description (fnil identity "")) - (if (:schema $) - (update $ :schema swagger/transform {:type :schema}) - $))]))})) + :swagger (swagger/swagger-spec + (merge + (if parameters + {::swagger/parameters + (into + (empty parameters) + (for [[k v] parameters] + [k (compile v options)]))}) + (if responses + {::swagger/responses + (into + (empty responses) + (for [[k response] responses] + [k (as-> response $ + (set/rename-keys $ {:body :schema}) + (if (:schema $) + (update $ :schema compile options) + $))]))}))) ;; :openapi handled in reitit.openapi/-get-apidocs-openapi (throw (ex-info diff --git a/modules/reitit-swagger/src/reitit/swagger.cljc b/modules/reitit-swagger/src/reitit/swagger.cljc index 9525035b..58a2a188 100644 --- a/modules/reitit-swagger/src/reitit/swagger.cljc +++ b/modules/reitit-swagger/src/reitit/swagger.cljc @@ -126,9 +126,15 @@ (if-let [endpoint (some->> c (keep transform-endpoint) (seq) (into {}))] [(swagger-path p (r/options router)) endpoint])) map-in-order #(->> % (apply concat) (apply array-map)) - paths (->> router (r/compiled-routes) (filter accept-route) (map transform-path) map-in-order)] + paths (->> router (r/compiled-routes) (filter accept-route) (map transform-path) map-in-order) + definitions (apply merge + (for [[_path path-data] paths + [_method data] path-data] + (:definitions data))) + paths-without-definitions (update-vals paths (fn [methods] + (update-vals methods #(dissoc % :definitions))))] {:status 200 - :body (meta-merge swagger {:paths paths})})) + :body (meta-merge swagger {:paths paths-without-definitions :definitions definitions})})) ([req res raise] (try (res (create-swagger req)) diff --git a/project.clj b/project.clj index 3b149de1..ca3ae3cc 100644 --- a/project.clj +++ b/project.clj @@ -37,7 +37,7 @@ [metosin/muuntaja "0.6.8"] [metosin/jsonista "0.3.7"] [metosin/sieppari "0.0.0-alpha13"] - [metosin/malli "0.11.0"] + [metosin/malli "0.12.0"] ;; https://clojureverse.org/t/depending-on-the-right-versions-of-jackson-libraries/5111 [com.fasterxml.jackson.core/jackson-core "2.15.1"] @@ -95,7 +95,7 @@ [metosin/muuntaja "0.6.8"] [metosin/sieppari "0.0.0-alpha13"] [metosin/jsonista "0.3.7"] - [metosin/malli "0.11.0"] + [metosin/malli "0.12.0"] [lambdaisland/deep-diff "0.0-47"] [meta-merge "1.0.0"] [com.bhauman/spell-spec "0.1.2"] diff --git a/test/cljc/reitit/swagger_test.clj b/test/cljc/reitit/swagger_test.clj index 2862edf1..40902704 100644 --- a/test/cljc/reitit/swagger_test.clj +++ b/test/cljc/reitit/swagger_test.clj @@ -12,7 +12,8 @@ [reitit.swagger :as swagger] [reitit.swagger-ui :as swagger-ui] [schema.core :as s] - [spec-tools.data-spec :as ds])) + [spec-tools.data-spec :as ds] + [malli.core :as mc])) (defn- normalize "Normalize format of swagger spec by converting it to json and back. @@ -22,6 +23,23 @@ j/write-value-as-string (j/read-value j/keyword-keys-object-mapper))) +(def malli-registry + (merge + (mc/base-schemas) + (mc/predicate-schemas) + (mc/type-schemas) + {::req-key [:or :keyword :string] + ::req-val [:or map? :string] + ::resp-map map? + ::resp-string [:string {:min 1}]})) + + +(def PutReqBody + (mc/schema [:map-of ::req-key ::req-val] {:registry malli-registry})) + +(def PutRespBody + (mc/schema [:or ::resp-map ::resp-string] {:registry malli-registry})) + (def app (ring/ring-handler (ring/router @@ -84,7 +102,13 @@ 500 {:description "fail"}} :handler (fn [{{{:keys [z]} :path xs :body} :parameters}] - {:status 200, :body {:total (+ (reduce + xs) z)}})}}]] + {:status 200, :body {:total (+ (reduce + xs) z)}})} + :put {:summary "plus put with definitions" + :parameters {:body PutReqBody} + :responses {200 {:body PutRespBody} + 500 {:description "fail"}} + :handler (fn [{{body :body} :parameters}] + {:status 200, :body (str "got " body)})}}]] ["/schema" {:coercion schema/coercion} ["/plus/*z" @@ -137,6 +161,15 @@ expected {:x-id #{::math} :swagger "2.0" :info {:title "my-api"} + :definitions {::req-key {:type "string" + :x-anyOf [{:type "string"} + {:type "string"}]} + ::req-val {:type "object" + :x-anyOf [{:type "object"} + {:type "string"}]} + ::resp-map {:type "object"}, + ::resp-string {:type "string" + :minLength 1}} :paths {"/api/spec/plus/{z}" {:patch {:parameters [] :summary "patch" :operationId "Patch" @@ -246,7 +279,23 @@ 400 {:schema {:type "string"} :description "kosh"} 500 {:description "fail"}} - :summary "plus with body"}} + :summary "plus with body"} + :put {:parameters [{:in "body" + :name "body" + :description "" + :required true + :schema + {:type "object" + :additionalProperties + {:$ref "#/definitions/reitit.swagger-test~1req-val"}}}] + :responses {200 + {:schema + {:$ref "#/definitions/reitit.swagger-test~1resp-map" + :x-anyOf [{:$ref "#/definitions/reitit.swagger-test~1resp-map"} + {:$ref "#/definitions/reitit.swagger-test~1resp-string"}]} + :description ""} + 500 {:description "fail"}} + :summary "plus put with definitions"}} "/api/schema/plus/{z}" {:get {:parameters [{:description "" :format "int32" :in "query"