diff --git a/modules/reitit-interceptors/src/reitit/http/interceptors/muuntaja.clj b/modules/reitit-interceptors/src/reitit/http/interceptors/muuntaja.clj index f697bfa4..47f00cbb 100644 --- a/modules/reitit-interceptors/src/reitit/http/interceptors/muuntaja.clj +++ b/modules/reitit-interceptors/src/reitit/http/interceptors/muuntaja.clj @@ -9,6 +9,16 @@ (defn- displace [x] (with-meta x {:displace true})) (defn- stripped [x] (select-keys x [:enter :leave :error])) +(defn- publish-swagger-data? [{:keys [form body]}] + (not (and (some? form) + (nil? body)))) + +(defn- swagger-data [parameters muuntaja] + (if (publish-swagger-data? parameters) + {:data {:swagger {:produces (displace (m/encodes muuntaja)) + :consumes (displace (m/decodes muuntaja))}}} + {})) + (defn format-interceptor "Interceptor for content-negotiation, request and response formatting. @@ -22,6 +32,8 @@ Encodes the response body using the `:muuntaja/response` key in request if the response doesn't have `Content-Type` header already set. + Swagger-data will be omitted when `:form`, but no `:body`, parameters are defined. + Optionally takes a default muuntaja instance as argument. | key | description | @@ -32,12 +44,11 @@ ([default-muuntaja] {:name ::format :spec ::spec - :compile (fn [{:keys [muuntaja]} _] + :compile (fn [{:keys [muuntaja parameters]} _] (if-let [muuntaja (or muuntaja default-muuntaja)] (merge (stripped (muuntaja.interceptor/format-interceptor muuntaja)) - {:data {:swagger {:produces (displace (m/encodes muuntaja)) - :consumes (displace (m/decodes muuntaja))}}})))})) + (swagger-data parameters muuntaja))))})) (defn format-negotiate-interceptor "Interceptor for content-negotiation. @@ -66,6 +77,8 @@ Decodes the request body into `:body-params` using the `:muuntaja/request` key in request if the `:body-params` doesn't already exist. + Swagger-data will be omitted when `:form`, but no `:body`, parameters are defined. + Optionally takes a default muuntaja instance as argument. | key | description | @@ -76,11 +89,12 @@ ([default-muuntaja] {:name ::format-request :spec ::spec - :compile (fn [{:keys [muuntaja]} _] + :compile (fn [{:keys [muuntaja parameters]} _] (if-let [muuntaja (or muuntaja default-muuntaja)] (merge (stripped (muuntaja.interceptor/format-request-interceptor muuntaja)) - {:data {:swagger {:consumes (displace (m/decodes muuntaja))}}})))})) + (when (publish-swagger-data? parameters) + {:data {:swagger {:consumes (displace (m/decodes muuntaja))}}}))))})) (defn format-response-interceptor "Interceptor for response formatting. @@ -88,6 +102,8 @@ Encodes the response body using the `:muuntaja/response` key in request if the response doesn't have `Content-Type` header already set. + Swagger-data will be omitted when `:form`, but no `:body`, parameters are defined. + Optionally takes a default muuntaja instance as argument. | key | description | @@ -98,8 +114,9 @@ ([default-muuntaja] {:name ::format-response :spec ::spec - :compile (fn [{:keys [muuntaja]} _] + :compile (fn [{:keys [muuntaja parameters]} _] (if-let [muuntaja (or muuntaja default-muuntaja)] (merge (stripped (muuntaja.interceptor/format-response-interceptor muuntaja)) - {:data {:swagger {:produces (displace (m/encodes muuntaja))}}})))})) + (when (publish-swagger-data? parameters) + {:data {:swagger {:produces (displace (m/encodes muuntaja))}}}))))})) diff --git a/modules/reitit-middleware/src/reitit/ring/middleware/muuntaja.clj b/modules/reitit-middleware/src/reitit/ring/middleware/muuntaja.clj index faa44e2c..abe62733 100644 --- a/modules/reitit-middleware/src/reitit/ring/middleware/muuntaja.clj +++ b/modules/reitit-middleware/src/reitit/ring/middleware/muuntaja.clj @@ -8,6 +8,16 @@ (defn- displace [x] (with-meta x {:displace true})) +(defn- publish-swagger-data? [{:keys [form body]}] + (not (and (some? form) + (nil? body)))) + +(defn- swagger-data [parameters muuntaja] + (if (publish-swagger-data? parameters) + {:data {:swagger {:produces (displace (m/encodes muuntaja)) + :consumes (displace (m/decodes muuntaja))}}} + {})) + (def format-middleware "Middleware for content-negotiation, request and response formatting. @@ -21,16 +31,18 @@ Encodes the response body using the `:muuntaja/response` key in request if the response doesn't have `Content-Type` header already set. + Swagger-data will be omitted when `:form`, but no `:body`, parameters are defined. + | key | description | | -------------|-------------| | `:muuntaja` | `muuntaja.core/Muuntaja` instance, does not mount if not set." {:name ::format :spec ::spec - :compile (fn [{:keys [muuntaja]} _] + :compile (fn [{:keys [muuntaja parameters]} _] (if muuntaja - {:data {:swagger {:produces (displace (m/encodes muuntaja)) - :consumes (displace (m/decodes muuntaja))}} - :wrap #(muuntaja.middleware/wrap-format % muuntaja)}))}) + (merge + (swagger-data parameters muuntaja) + {:wrap #(muuntaja.middleware/wrap-format % muuntaja)})))}) (def format-negotiate-middleware "Middleware for content-negotiation. @@ -54,15 +66,19 @@ Decodes the request body into `:body-params` using the `:muuntaja/request` key in request if the `:body-params` doesn't already exist. + Swagger-data will be omitted when `:form`, but no `:body`, parameters are defined. + | key | description | | -------------|-------------| | `:muuntaja` | `muuntaja.core/Muuntaja` instance, does not mount if not set." {:name ::format-request :spec ::spec - :compile (fn [{:keys [muuntaja]} _] + :compile (fn [{:keys [muuntaja parameters]} _] (if muuntaja - {:data {:swagger {:consumes (displace (m/decodes muuntaja))}} - :wrap #(muuntaja.middleware/wrap-format-request % muuntaja)}))}) + (merge + (when (publish-swagger-data? parameters) + {:data {:swagger {:consumes (displace (m/decodes muuntaja))}}}) + {:wrap #(muuntaja.middleware/wrap-format-request % muuntaja)})))}) (def format-response-middleware "Middleware for response formatting. @@ -70,12 +86,16 @@ Encodes the response body using the `:muuntaja/response` key in request if the response doesn't have `Content-Type` header already set. + Swagger-data will be omitted when `:form`, but no `:body`, parameters are defined. + | key | description | | -------------|-------------| | `:muuntaja` | `muuntaja.core/Muuntaja` instance, does not mount if not set." {:name ::format-response :spec ::spec - :compile (fn [{:keys [muuntaja]} _] + :compile (fn [{:keys [muuntaja parameters]} _] (if muuntaja - {:data {:swagger {:produces (displace (m/encodes muuntaja))}} - :wrap #(muuntaja.middleware/wrap-format-response % muuntaja)}))}) + (merge + (when (publish-swagger-data? parameters) + {:data {:swagger {:produces (displace (m/encodes muuntaja))}}}) + {:wrap #(muuntaja.middleware/wrap-format-response % muuntaja)})))}) diff --git a/test/clj/reitit/http/interceptors/muuntaja_test.clj b/test/clj/reitit/http/interceptors/muuntaja_test.clj index 22c402df..b7c086de 100644 --- a/test/clj/reitit/http/interceptors/muuntaja_test.clj +++ b/test/clj/reitit/http/interceptors/muuntaja_test.clj @@ -36,20 +36,25 @@ ["/just-edn" {:muuntaja just-edn :get identity}] + ["/form-params" + {:post {:parameters {:form {:x string?}} + :handler identity}}] ["/swagger.json" {:get {:no-doc true :handler (swagger/create-swagger-handler)}}]] {:data {:muuntaja m/instance :interceptors [(muuntaja/format-interceptor)]}}) {:executor sieppari/executor}) - spec (fn [path] + spec (fn [method path] (let [path (keyword path)] (-> {:request-method :get :uri "/swagger.json"} (app) :body (->> (m/decode m/instance "application/json")) - :paths path :get))) - produces (comp set :produces spec) - consumes (comp set :consumes spec)] + :paths path method))) + produces (comp set :produces (partial spec :get)) + consumes (comp set :consumes (partial spec :get)) + post-produces (comp set :produces (partial spec :post)) + post-consumes (comp set :consumes (partial spec :post))] (testing "with defaults" (let [path "/defaults"] @@ -85,7 +90,12 @@ (let [path "/just-edn"] (is (= #{"application/edn"} (produces path) - (consumes path))))))) + (consumes path))))) + (testing "form parameters swagger-data" + (let [path "/form-params"] + (is (= #{} + (post-produces path) + (post-consumes path))))))) (deftest muuntaja-swagger-parts-test (let [app (http/ring-handler @@ -103,17 +113,35 @@ (muuntaja/format-response-interceptor) (muuntaja/format-request-interceptor)] :get identity}] + ["/form-request" + {:interceptors [(muuntaja/format-negotiate-interceptor) + (muuntaja/format-request-interceptor)] + :post {:parameters {:form {:x string?}} + :handler identity}}] + ["/form-response" + {:interceptors [(muuntaja/format-negotiate-interceptor) + (muuntaja/format-response-interceptor)] + :post {:parameters {:form {:x string?}} + :handler identity}}] + ["/form-with-both" + {:interceptors [(muuntaja/format-negotiate-interceptor) + (muuntaja/format-response-interceptor) + (muuntaja/format-request-interceptor)] + :post {:parameters {:form {:x string?}} + :handler identity}}] ["/swagger.json" {:get {:no-doc true :handler (swagger/create-swagger-handler)}}]] {:data {:muuntaja m/instance}}) {:executor sieppari/executor}) - spec (fn [path] + spec (fn [method path] (-> {:request-method :get :uri "/swagger.json"} - (app) :body :paths (get path) :get)) - produces (comp :produces spec) - consumes (comp :consumes spec)] + (app) :body :paths (get path) method)) + produces (comp :produces (partial spec :get)) + consumes (comp :consumes (partial spec :get)) + post-produces (comp :produces (partial spec :post)) + post-consumes (comp :consumes (partial spec :post))] (testing "just request formatting" (let [path "/request"] @@ -133,7 +161,7 @@ (produces path))) (is (nil? (consumes path))))) - (testing "just response formatting" + (testing "request and response formatting" (let [path "/both"] (is (= #{"application/json" "application/transit+msgpack" @@ -144,4 +172,16 @@ "application/transit+msgpack" "application/transit+json" "application/edn"} - (consumes path))))))) + (consumes path))))) + (testing "just request formatting for form params" + (let [path "/form-request"] + (is (nil? (post-produces path))) + (is (nil? (post-consumes path))))) + (testing "just response formatting for form params" + (let [path "/form-response"] + (is (nil? (post-produces path))) + (is (nil? (post-consumes path))))) + (testing "just request formatting for form params" + (let [path "/form-with-both"] + (is (nil? (post-produces path))) + (is (nil? (post-consumes path))))))) diff --git a/test/clj/reitit/ring/middleware/muuntaja_test.clj b/test/clj/reitit/ring/middleware/muuntaja_test.clj index f3d7fa31..0cd5beed 100644 --- a/test/clj/reitit/ring/middleware/muuntaja_test.clj +++ b/test/clj/reitit/ring/middleware/muuntaja_test.clj @@ -34,19 +34,24 @@ ["/just-edn" {:muuntaja just-edn :get identity}] + ["/form-params" + {:post {:parameters {:form {:x string?}} + :handler identity}}] ["/swagger.json" {:get {:no-doc true :handler (swagger/create-swagger-handler)}}]] {:data {:muuntaja m/instance :middleware [muuntaja/format-middleware]}})) - spec (fn [path] + spec (fn [method path] (let [path (keyword path)] (-> {:request-method :get :uri "/swagger.json"} (app) :body (->> (m/decode m/instance "application/json")) - :paths path :get))) - produces (comp set :produces spec) - consumes (comp set :consumes spec)] + :paths path method))) + produces (comp set :produces (partial spec :get)) + consumes (comp set :consumes (partial spec :get)) + post-produces (comp set :produces (partial spec :post)) + post-consumes (comp set :consumes (partial spec :post))] (testing "with defaults" (let [path "/defaults"] @@ -82,7 +87,12 @@ (let [path "/just-edn"] (is (= #{"application/edn"} (produces path) - (consumes path))))))) + (consumes path))))) + (testing "form parameters swagger-data" + (let [path "/form-params"] + (is (= #{} + (post-produces path) + (post-consumes path))))))) (deftest muuntaja-swagger-parts-test (let [app (ring/ring-handler @@ -100,16 +110,34 @@ muuntaja/format-response-middleware muuntaja/format-request-middleware] :get identity}] + ["/form-request" + {:middleware [muuntaja/format-negotiate-middleware + muuntaja/format-request-middleware] + :post {:parameters {:form {:x string?}} + :handler identity}}] + ["/form-response" + {:middleware [muuntaja/format-negotiate-middleware + muuntaja/format-response-middleware] + :post {:parameters {:form {:x string?}} + :handler identity}}] + ["/form-with-both" + {:middleware [muuntaja/format-negotiate-middleware + muuntaja/format-response-middleware + muuntaja/format-request-middleware] + :post {:parameters {:form {:x string?}} + :handler identity}}] ["/swagger.json" {:get {:no-doc true :handler (swagger/create-swagger-handler)}}]] {:data {:muuntaja m/instance}})) - spec (fn [path] + spec (fn [method path] (-> {:request-method :get :uri "/swagger.json"} - (app) :body :paths (get path) :get)) - produces (comp :produces spec) - consumes (comp :consumes spec)] + (app) :body :paths (get path) method)) + produces (comp :produces (partial spec :get)) + consumes (comp :consumes (partial spec :get)) + post-produces (comp :produces (partial spec :post)) + post-consumes (comp :consumes (partial spec :post))] (testing "just request formatting" (let [path "/request"] @@ -129,7 +157,7 @@ (produces path))) (is (nil? (consumes path))))) - (testing "just response formatting" + (testing "request and response formatting" (let [path "/both"] (is (= #{"application/json" "application/transit+msgpack" @@ -140,4 +168,16 @@ "application/transit+msgpack" "application/transit+json" "application/edn"} - (consumes path))))))) + (consumes path))))) + (testing "just request formatting for form params" + (let [path "/form-request"] + (is (nil? (post-produces path))) + (is (nil? (post-consumes path))))) + (testing "just response formatting for form params" + (let [path "/form-response"] + (is (nil? (post-produces path))) + (is (nil? (post-consumes path))))) + (testing "just request formatting for form params" + (let [path "/form-with-both"] + (is (nil? (post-produces path))) + (is (nil? (post-consumes path)))))))