From d8e28e153b1733986708895d2bc15fbc0de20c93 Mon Sep 17 00:00:00 2001 From: Joel Kaasinen Date: Fri, 17 Mar 2023 14:43:49 +0200 Subject: [PATCH] fix: swagger multipart support 1. For spec we were including some extra stuff in the parameter specification: {:description "", :in "formData", :name "file", :properties {"bytes" {:format "byte", :type "string"}, "content-type" {:type "string"}, "filename" {:type "string"}}, :required ["filename" "content-type" "bytes"], :type "file"} 2. For malli the :type changed from "file" to "string" because of openapi changes. Now openapi and swagger both get the right type. 3. Test for swagger multipart support --- .../reitit/http/interceptors/multipart.clj | 4 +- .../reitit-malli/src/reitit/ring/malli.cljc | 6 ++- test/cljc/reitit/swagger_test.clj | 49 +++++++++++++++++++ 3 files changed, 55 insertions(+), 4 deletions(-) diff --git a/modules/reitit-interceptors/src/reitit/http/interceptors/multipart.clj b/modules/reitit-interceptors/src/reitit/http/interceptors/multipart.clj index 4a2d4ba1..b4bd02e5 100644 --- a/modules/reitit-interceptors/src/reitit/http/interceptors/multipart.clj +++ b/modules/reitit-interceptors/src/reitit/http/interceptors/multipart.clj @@ -19,7 +19,7 @@ "Spec for file param created by ring.middleware.multipart-params.temp-file store." (st/spec {:spec (s/keys :req-un [::filename ::content-type ::tempfile ::size]) - :swagger/type "file" + :swagger {:type "file"} :openapi {:type "string" :format "binary"}})) @@ -27,7 +27,7 @@ "Spec for file param created by ring.middleware.multipart-params.byte-array store." (st/spec {:spec (s/keys :req-un [::filename ::content-type ::bytes]) - :swagger/type "file" + :swagger {:type "file"} :openapi {:type "string" :format "binary"}})) diff --git a/modules/reitit-malli/src/reitit/ring/malli.cljc b/modules/reitit-malli/src/reitit/ring/malli.cljc index 1ccc1959..9815fef5 100644 --- a/modules/reitit-malli/src/reitit/ring/malli.cljc +++ b/modules/reitit-malli/src/reitit/ring/malli.cljc @@ -4,7 +4,8 @@ #?(:clj (def temp-file-part "Schema for file param created by ring.middleware.multipart-params.temp-file store." - [:map {:json-schema {:type "string" + [:map {:swagger {:type "file"} + :json-schema {:type "string" :format "binary"}} [:filename string?] [:content-type string?] @@ -14,7 +15,8 @@ #?(:clj (def bytes-part "Schema for file param created by ring.middleware.multipart-params.byte-array store." - [:map {:json-schema {:type "string" + [:map {:swagger {:type "file"} + :json-schema {:type "string" :format "binary"}} [:filename string?] [:content-type string?] diff --git a/test/cljc/reitit/swagger_test.clj b/test/cljc/reitit/swagger_test.clj index 542b7ebd..d2d18c31 100644 --- a/test/cljc/reitit/swagger_test.clj +++ b/test/cljc/reitit/swagger_test.clj @@ -1,16 +1,27 @@ (ns reitit.swagger-test (:require [clojure.test :refer [deftest is testing]] + [jsonista.core :as j] [muuntaja.core :as m] [reitit.coercion.malli :as malli] [reitit.coercion.schema :as schema] [reitit.coercion.spec :as spec] + [reitit.http.interceptors.multipart] [reitit.ring :as ring] + [reitit.ring.malli] [reitit.ring.coercion :as rrc] [reitit.swagger :as swagger] [reitit.swagger-ui :as swagger-ui] [schema.core :as s] [spec-tools.data-spec :as ds])) +(defn- normalize + "Normalize format of swagger spec by converting it to json and back. + Handles differences like :q vs \"q\" in swagger generation." + [data] + (-> data + j/write-value-as-string + (j/read-value j/keyword-keys-object-mapper))) + (def app (ring/ring-handler (ring/router @@ -410,3 +421,41 @@ :handler (swagger/create-swagger-handler)}}]])) output (with-out-str (app {:request-method :get, :uri "/swagger.json"}))] (is (.contains output "WARN"))))) + +(deftest multipart-test + (doseq [[coercion file-schema string-schema] + [[#'malli/coercion + reitit.ring.malli/bytes-part + :string] + [#'spec/coercion + reitit.http.interceptors.multipart/bytes-part + string?]]] + (testing coercion + (let [app (ring/ring-handler + (ring/router + [["/upload" + {:post {:decription "upload" + :coercion @coercion + :parameters {:multipart {:file file-schema + :more string-schema}} + :handler identity}}] + ["/swagger.json" + {:get {:no-doc true + :handler (swagger/create-swagger-handler)}}]] + {:data {:middleware [swagger/swagger-feature]}})) + spec (-> {:request-method :get + :uri "/swagger.json"} + app + :body)] + (is (= [{:description "" + :in "formData" + :name "file" + :required true + :type "file"} + {:description "" + :in "formData" + :name "more" + :required true + :type "string"}] + (normalize + (get-in spec [:paths "/upload" :post :parameters]))))))))