From 229171c7e3bee44f121d9f60a3a94e2005dc70b9 Mon Sep 17 00:00:00 2001 From: Wes Morgan Date: Mon, 6 Mar 2023 12:15:20 -0700 Subject: [PATCH 1/9] Move more of swagger gen into malli lib ...so we can fix #558. --- .../src/reitit/coercion/malli.cljc | 67 ++++++------------- 1 file changed, 19 insertions(+), 48 deletions(-) diff --git a/modules/reitit-malli/src/reitit/coercion/malli.cljc b/modules/reitit-malli/src/reitit/coercion/malli.cljc index 87388add6..18281ddfe 100644 --- a/modules/reitit-malli/src/reitit/coercion/malli.cljc +++ b/modules/reitit-malli/src/reitit/coercion/malli.cljc @@ -75,33 +75,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 ;; @@ -145,28 +118,26 @@ (reify coercion/Coercion (-get-name [_] :malli) (-get-options [_] opts) - (-get-apidocs [_ specification {:keys [parameters responses]}] + (-get-apidocs [this specification {:keys [parameters responses]}] (case specification - :swagger (merge - (if parameters - {:parameters - (->> (for [[in schema] parameters - parameter (extract-parameter in (compile schema options) options)] - parameter) - (into []))}) - (if responses - {:responses - (into - (empty responses) - (for [[status response] responses] - [status (as-> response $ - (set/rename-keys $ {:body :schema}) - (update $ :description (fnil identity "")) - (if (:schema $) - (-> $ - (update :schema compile options) - (update :schema swagger/transform {:type :schema})) - $))]))})) + :swagger (swagger/swagger-spec + (merge + (if parameters + {::swagger/parameters + (into + (empty parameters) + (for [[k v] parameters] + [k (coercion/-compile-model this v nil)]))}) + (if responses + {::swagger/responses + (into + (empty responses) + (for [[k response] responses] + [k (as-> response $ + (set/rename-keys $ {:body :schema}) + (if (:schema $) + (update $ :schema #(coercion/-compile-model this % nil)) + $))]))}))) (throw (ex-info (str "Can't produce Schema apidocs for " specification) From 4f31304a1a8fcae8d235d5569571969fc7d4c0cb Mon Sep 17 00:00:00 2001 From: Wes Morgan Date: Mon, 6 Mar 2023 12:16:48 -0700 Subject: [PATCH 2/9] Lift definitions to root of swagger.json ...so that all of the absolute $ref's to them will resolve --- modules/reitit-swagger/src/reitit/swagger.cljc | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/modules/reitit-swagger/src/reitit/swagger.cljc b/modules/reitit-swagger/src/reitit/swagger.cljc index 3c3403cbc..6c18d5bb7 100644 --- a/modules/reitit-swagger/src/reitit/swagger.cljc +++ b/modules/reitit-swagger/src/reitit/swagger.cljc @@ -102,9 +102,17 @@ (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 (reduce-kv + (fn [ds _ v] + (let [ks (keys v)] + (merge ds (apply merge + (for [k ks] + (when-let [method-map (get v k)] + (:definitions method-map))))))) + {} paths)] {:status 200 - :body (meta-merge swagger {:paths paths})})) + :body (meta-merge swagger {:paths paths :definitions definitions})})) ([req res raise] (try (res (create-swagger req)) From 182524baac575ab10bbcf2270effbcf4822f008d Mon Sep 17 00:00:00 2001 From: Wes Morgan Date: Mon, 17 Apr 2023 11:35:28 -0600 Subject: [PATCH 3/9] Update swagger test expectations for latest malli changes --- test/cljc/reitit/swagger_test.clj | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/cljc/reitit/swagger_test.clj b/test/cljc/reitit/swagger_test.clj index d2d18c310..38f6bf0cc 100644 --- a/test/cljc/reitit/swagger_test.clj +++ b/test/cljc/reitit/swagger_test.clj @@ -138,6 +138,7 @@ expected {:x-id #{::math} :swagger "2.0" :info {:title "my-api"} + :definitions {} :paths {"/api/spec/plus/{z}" {:patch {:parameters [] :summary "patch" :operationId "Patch" @@ -223,6 +224,7 @@ 400 {:schema {:type "string"} :description "kosh"} 500 {:description "fail"}} + :definitions nil :summary "plus"} :post {:parameters [{:in "body", :name "body", @@ -247,6 +249,7 @@ 400 {:schema {:type "string"} :description "kosh"} 500 {:description "fail"}} + :definitions nil :summary "plus with body"}} "/api/schema/plus/{z}" {:get {:parameters [{:description "" :format "int32" From 937768651e659203151c121e119d28c85bf61a32 Mon Sep 17 00:00:00 2001 From: Wes Morgan Date: Thu, 20 Apr 2023 12:39:08 -0600 Subject: [PATCH 4/9] Add malli swagger test w/ definitions --- test/cljc/reitit/swagger_test.clj | 75 +++++++++++++++++++++++++++++-- 1 file changed, 71 insertions(+), 4 deletions(-) diff --git a/test/cljc/reitit/swagger_test.clj b/test/cljc/reitit/swagger_test.clj index 38f6bf0cc..3da0c6b03 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" @@ -138,7 +162,15 @@ expected {:x-id #{::math} :swagger "2.0" :info {:title "my-api"} - :definitions {} + :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" @@ -250,7 +282,42 @@ :description "kosh"} 500 {:description "fail"}} :definitions nil - :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"} + :definitions {::req-key + {:type "string" + :x-anyOf [{:type "string"} + {:type "string"}]} + ::req-val + {:type "object" + :x-anyOf [{:type "object"} + {:type "string"}]}}}}] + :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"}] + :definitions {::resp-map {:type "object"} + ::resp-string + {:type "string", :minLength 1}}} + :description ""} + 500 {:description "fail"}} + :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}} + :summary "plus put with definitions"}} "/api/schema/plus/{z}" {:get {:parameters [{:description "" :format "int32" :in "query" From 59812a350f278820f912d38e361384b5a10c3814 Mon Sep 17 00:00:00 2001 From: Wes Morgan Date: Tue, 9 May 2023 10:33:54 -0600 Subject: [PATCH 5/9] Update malli swagger test expectations for definitions ...which should only be at the top level now. --- test/cljc/reitit/swagger_test.clj | 25 ++----------------------- 1 file changed, 2 insertions(+), 23 deletions(-) diff --git a/test/cljc/reitit/swagger_test.clj b/test/cljc/reitit/swagger_test.clj index 3da0c6b03..9b8f604c7 100644 --- a/test/cljc/reitit/swagger_test.clj +++ b/test/cljc/reitit/swagger_test.clj @@ -256,7 +256,6 @@ 400 {:schema {:type "string"} :description "kosh"} 500 {:description "fail"}} - :definitions nil :summary "plus"} :post {:parameters [{:in "body", :name "body", @@ -281,7 +280,6 @@ 400 {:schema {:type "string"} :description "kosh"} 500 {:description "fail"}} - :definitions nil :summary "plus with body"} :put {:parameters [{:in "body" :name "body" @@ -290,33 +288,14 @@ :schema {:type "object" :additionalProperties - {:$ref "#/definitions/reitit.swagger-test~1req-val"} - :definitions {::req-key - {:type "string" - :x-anyOf [{:type "string"} - {:type "string"}]} - ::req-val - {:type "object" - :x-anyOf [{:type "object"} - {:type "string"}]}}}}] + {:$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"}] - :definitions {::resp-map {:type "object"} - ::resp-string - {:type "string", :minLength 1}}} + {:$ref "#/definitions/reitit.swagger-test~1resp-string"}]} :description ""} 500 {:description "fail"}} - :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}} :summary "plus put with definitions"}} "/api/schema/plus/{z}" {:get {:parameters [{:description "" :format "int32" From b316840ea0dae671aa9c5e91210985fe72b69c3e Mon Sep 17 00:00:00 2001 From: Joel Kaasinen Date: Wed, 30 Aug 2023 08:39:36 +0300 Subject: [PATCH 6/9] fix: compile instead of -compile-model in malli.cljc -compile-model now takes a vector of models, so (-compile-model this model nil) fails. Just use compile directly like master does. --- modules/reitit-malli/src/reitit/coercion/malli.cljc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/reitit-malli/src/reitit/coercion/malli.cljc b/modules/reitit-malli/src/reitit/coercion/malli.cljc index eb97457e0..89dce54cc 100644 --- a/modules/reitit-malli/src/reitit/coercion/malli.cljc +++ b/modules/reitit-malli/src/reitit/coercion/malli.cljc @@ -136,7 +136,7 @@ (into (empty parameters) (for [[k v] parameters] - [k (coercion/-compile-model this v nil)]))}) + [k (compile v options)]))}) (if responses {::swagger/responses (into @@ -145,7 +145,7 @@ [k (as-> response $ (set/rename-keys $ {:body :schema}) (if (:schema $) - (update $ :schema #(coercion/-compile-model this % nil)) + (update $ :schema compile options) $))]))}))) ;; :openapi handled in reitit.openapi/-get-apidocs-openapi (throw From 241c8367e368abc7078434f3b6a4a526fd8ce09d Mon Sep 17 00:00:00 2001 From: Joel Kaasinen Date: Wed, 30 Aug 2023 09:37:55 +0300 Subject: [PATCH 7/9] feat: dissoc definitions from swagger methods we only want the definitions on the very top level of the swagger doc --- .../reitit-swagger/src/reitit/swagger.cljc | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/modules/reitit-swagger/src/reitit/swagger.cljc b/modules/reitit-swagger/src/reitit/swagger.cljc index 496c0ada9..3938eec9f 100644 --- a/modules/reitit-swagger/src/reitit/swagger.cljc +++ b/modules/reitit-swagger/src/reitit/swagger.cljc @@ -127,16 +127,17 @@ [(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) - definitions (reduce-kv - (fn [ds _ v] - (let [ks (keys v)] - (merge ds (apply merge - (for [k ks] - (when-let [method-map (get v k)] - (:definitions method-map))))))) - {} paths)] + definitions (apply merge + (for [[_path path-data] paths + [_method data] path-data] + (:definitions data))) + paths-without-definitions (into {} + (for [[path path-data] paths] + [path (into {} + (for [[method data] path-data] + [method (dissoc data :definitions)]))]))] {:status 200 - :body (meta-merge swagger {:paths paths :definitions definitions})})) + :body (meta-merge swagger {:paths paths-without-definitions :definitions definitions})})) ([req res raise] (try (res (create-swagger req)) From 497da675b92d2d50b00feaf3ff662145a04a250d Mon Sep 17 00:00:00 2001 From: Joel Kaasinen Date: Fri, 1 Sep 2023 10:37:17 +0300 Subject: [PATCH 8/9] refactor: use update-vals --- modules/reitit-swagger/src/reitit/swagger.cljc | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/modules/reitit-swagger/src/reitit/swagger.cljc b/modules/reitit-swagger/src/reitit/swagger.cljc index 3938eec9f..58a2a1881 100644 --- a/modules/reitit-swagger/src/reitit/swagger.cljc +++ b/modules/reitit-swagger/src/reitit/swagger.cljc @@ -131,11 +131,8 @@ (for [[_path path-data] paths [_method data] path-data] (:definitions data))) - paths-without-definitions (into {} - (for [[path path-data] paths] - [path (into {} - (for [[method data] path-data] - [method (dissoc data :definitions)]))]))] + paths-without-definitions (update-vals paths (fn [methods] + (update-vals methods #(dissoc % :definitions))))] {:status 200 :body (meta-merge swagger {:paths paths-without-definitions :definitions definitions})})) ([req res raise] From ee462c9981edd1edc89c0609656c807a403da050 Mon Sep 17 00:00:00 2001 From: Joel Kaasinen Date: Fri, 1 Sep 2023 10:56:43 +0300 Subject: [PATCH 9/9] bump malli dep --- project.clj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/project.clj b/project.clj index 3b149de10..ca3ae3cc1 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"]