Merge pull request #417 from Koura/issue-217-consume-form-params

Issue 217 consume form params
This commit is contained in:
Tommi Reiman 2020-09-30 12:25:52 +03:00 committed by GitHub
commit 39ec264da8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 207 additions and 41 deletions

View file

@ -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))}}}))))}))

View file

@ -11,6 +11,10 @@
:params - a merged map of all types of parameter"
[]
{:name ::parameters
:compile (fn [{:keys [parameters]} _]
(if (and (some? (:form parameters)) (nil? (:body parameters)))
{:data {:swagger {:consumes ["application/x-www-form-urlencoded"]}}}
{}))
:enter (fn [ctx]
(let [request (:request ctx)]
(assoc ctx :request (params/params-request request))))})

View file

@ -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)})))})

View file

@ -10,4 +10,8 @@
:form-params - a map of parameters from the body
:params - a merged map of all types of parameter"
{:name ::parameters
:compile (fn [{:keys [parameters]} _]
(if (and (some? (:form parameters)) (nil? (:body parameters)))
{:data {:swagger {:consumes ["application/x-www-form-urlencoded"]}}}
{}))
:wrap params/wrap-params})

View file

@ -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)))))))

View file

@ -2,7 +2,8 @@
(:require [clojure.test :refer [deftest testing is]]
[reitit.http.interceptors.parameters :as parameters]
[reitit.http :as http]
[reitit.interceptor.sieppari :as sieppari]))
[reitit.interceptor.sieppari :as sieppari]
[reitit.swagger :as swagger]))
(deftest parameters-test
(let [app (http/ring-handler
@ -15,3 +16,23 @@
(app {:request-method :get
:uri "/ping"
:query-string "kikka=kukka"})))))
(deftest parameters-swagger-test
(let [app (http/ring-handler
(http/router
[["/form-params" {:post {:parameters {:form {:x string?}}
:handler identity}}]
["/body-params" {:post {:parameters {:body {:x string?}}
:handler identity}}]
["/swagger.json" {:get {:no-doc true
:handler (swagger/create-swagger-handler)}}]]
{:data {:interceptors [(parameters/parameters-interceptor)]}})
 {:executor sieppari/executor})
spec (fn [path]
(-> {:request-method :get :uri "/swagger.json"}
app
(get-in [:body :paths path :post])))]
(testing "with form parameters"
(is (= ["application/x-www-form-urlencoded"] (:consumes (spec "/form-params")))))
(testing "with body parameters"
(is (= nil (:consumes (spec "/body-params")))))))

View file

@ -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)))))))

View file

@ -1,7 +1,8 @@
(ns reitit.ring.middleware.parameters-test
(:require [clojure.test :refer [deftest testing is]]
[reitit.ring.middleware.parameters :as parameters]
[reitit.ring :as ring]))
[reitit.ring :as ring]
[reitit.swagger :as swagger]))
(deftest parameters-test
(let [app (ring/ring-handler
@ -13,3 +14,22 @@
(app {:request-method :get
:uri "/ping"
:query-string "kikka=kukka"})))))
(deftest parameters-swagger-test
(let [app (ring/ring-handler
(ring/router
[["/form-params" {:post {:parameters {:form {:x string?}}
:handler identity}}]
["/body-params" {:post {:parameters {:body {:x string?}}
:handler identity}}]
["/swagger.json" {:get {:no-doc true
:handler (swagger/create-swagger-handler)}}]]
{:data {:middleware [parameters/parameters-middleware]}}))
spec (fn [path]
(-> {:request-method :get :uri "/swagger.json"}
app
(get-in [:body :paths path :post])))]
(testing "with form parameters"
(is (= ["application/x-www-form-urlencoded"] (:consumes (spec "/form-params")))))
(testing "with body parameters"
(is (= nil (:consumes (spec "/body-params")))))))