This commit is contained in:
Tommi Reiman 2023-05-21 20:16:45 +03:00
parent 550ea6da58
commit 3f265888a4
4 changed files with 138 additions and 139 deletions

View file

@ -67,8 +67,8 @@
fragment (when (.hasFragment uri) fragment (when (.hasFragment uri)
(.getFragment uri)) (.getFragment uri))
match (assoc match match (assoc match
:query-params q :query-params q
:fragment fragment) :fragment fragment)
;; Return uncoerced values if coercion is not enabled - so ;; Return uncoerced values if coercion is not enabled - so
;; that tha parameters are always accessible from same property. ;; that tha parameters are always accessible from same property.
parameters (or (coerce! match) parameters (or (coerce! match)

View file

@ -267,14 +267,14 @@
(let [pong (constantly "ok") (let [pong (constantly "ok")
routes ["/api" {:mw [:api]} routes ["/api" {:mw [:api]}
["/ping" :kikka] ["/ping" :kikka]
["/user/:id" {:parameters {:id "String"}} ["/user/:id" {:parameters {:path {:id :string}}}
["/:sub-id" {:parameters {:sub-id "String"}}]] ["/:sub-id" {:parameters {:path {:sub-id :string}}}]]
["/pong" pong] ["/pong" pong]
["/admin" {:mw [:admin] :roles #{:admin}} ["/admin" {:mw [:admin] :roles #{:admin}}
["/user" {:roles ^:replace #{:user}}] ["/user" {:roles ^:replace #{:user}}]
["/db" {:mw [:db]}]]] ["/db" {:mw [:db]}]]]
expected [["/api/ping" {:mw [:api], :name :kikka}] expected [["/api/ping" {:mw [:api], :name :kikka}]
["/api/user/:id/:sub-id" {:mw [:api], :parameters {:id "String", :sub-id "String"}}] ["/api/user/:id/:sub-id" {:mw [:api], :parameters {:path [{:id :string} {:sub-id :string}]}}]
["/api/pong" {:mw [:api], :handler pong}] ["/api/pong" {:mw [:api], :handler pong}]
["/api/admin/user" {:mw [:api :admin], :roles #{:user}}] ["/api/admin/user" {:mw [:api :admin], :roles #{:user}}]
["/api/admin/db" {:mw [:api :admin :db], :roles #{:admin}}]] ["/api/admin/db" {:mw [:api :admin :db], :roles #{:admin}}]]
@ -282,7 +282,7 @@
(is (= expected (impl/resolve-routes routes (r/default-router-options)))) (is (= expected (impl/resolve-routes routes (r/default-router-options))))
(is (= (r/map->Match (is (= (r/map->Match
{:template "/api/user/:id/:sub-id" {:template "/api/user/:id/:sub-id"
:data {:mw [:api], :parameters {:id "String", :sub-id "String"}} :data {:mw [:api], :parameters {:path [{:id :string} {:sub-id :string}]}}
:path "/api/user/1/2" :path "/api/user/1/2"
:path-params {:id "1", :sub-id "2"}}) :path-params {:id "1", :sub-id "2"}})
(r/match-by-path router "/api/user/1/2")))))) (r/match-by-path router "/api/user/1/2"))))))

View file

@ -32,101 +32,101 @@
(def app (def app
(ring/ring-handler (ring/ring-handler
(ring/router (ring/router
["/api" ["/api"
{:openapi {:id ::math}} {:openapi {:id ::math}}
["/openapi.json" ["/openapi.json"
{:get {:no-doc true {:get {:no-doc true
:openapi {:info {:title "my-api" :openapi {:info {:title "my-api"
:version "0.0.1"}} :version "0.0.1"}}
:handler (openapi/create-openapi-handler)}}] :handler (openapi/create-openapi-handler)}}]
["/spec" {:coercion spec/coercion} ["/spec" {:coercion spec/coercion}
["/plus/:z" ["/plus/:z"
{:get {:summary "plus" {:get {:summary "plus"
:tags [:plus :spec] :tags [:plus :spec]
:parameters {:query {:x int?, :y int?} :parameters {:query {:x int?, :y int?}
:path {:z int?}} :path {:z int?}}
:openapi {:operationId "spec-plus" :openapi {:operationId "spec-plus"
:deprecated true :deprecated true
:responses {400 {:description "kosh" :responses {400 {:description "kosh"
:content {"application/json" {:schema {:type "string"}}}}}} :content {"application/json" {:schema {:type "string"}}}}}}
:responses {200 {:description "success" :responses {200 {:description "success"
:body {:total int?}} :body {:total int?}}
500 {:description "fail"}} 500 {:description "fail"}}
:handler (fn [{{{:keys [x y]} :query :handler (fn [{{{:keys [x y]} :query
{:keys [z]} :path} :parameters}] {:keys [z]} :path} :parameters}]
{:status 200, :body {:total (+ x y z)}})} {:status 200, :body {:total (+ x y z)}})}
:post {:summary "plus with body" :post {:summary "plus with body"
:parameters {:body (ds/maybe [int?]) :parameters {:body (ds/maybe [int?])
:path {:z int?}} :path {:z int?}}
:openapi {:responses {400 {:content {"application/json" {:schema {:type "string"}}} :openapi {:responses {400 {:content {"application/json" {:schema {:type "string"}}}
:description "kosh"}}} :description "kosh"}}}
:responses {200 {:description "success" :responses {200 {:description "success"
:body {:total int?}} :body {:total int?}}
500 {:description "fail"}} 500 {:description "fail"}}
:handler (fn [{{{:keys [z]} :path :handler (fn [{{{:keys [z]} :path
xs :body} :parameters}] xs :body} :parameters}]
{:status 200, :body {:total (+ (reduce + xs) z)}})}}]] {:status 200, :body {:total (+ (reduce + xs) z)}})}}]]
["/malli" {:coercion malli/coercion} ["/malli" {:coercion malli/coercion}
["/plus/*z" ["/plus/*z"
{:get {:summary "plus" {:get {:summary "plus"
:tags [:plus :malli] :tags [:plus :malli]
:parameters {:query [:map [:x int?] [:y int?]] :parameters {:query [:map [:x int?] [:y int?]]
:path [:map [:z int?]]} :path [:map [:z int?]]}
:openapi {:responses {400 {:description "kosh" :openapi {:responses {400 {:description "kosh"
:content {"application/json" {:schema {:type "string"}}}}}} :content {"application/json" {:schema {:type "string"}}}}}}
:responses {200 {:description "success" :responses {200 {:description "success"
:body [:map [:total int?]]} :body [:map [:total int?]]}
500 {:description "fail"}} 500 {:description "fail"}}
:handler (fn [{{{:keys [x y]} :query :handler (fn [{{{:keys [x y]} :query
{:keys [z]} :path} :parameters}] {:keys [z]} :path} :parameters}]
{:status 200, :body {:total (+ x y z)}})} {:status 200, :body {:total (+ x y z)}})}
:post {:summary "plus with body" :post {:summary "plus with body"
:parameters {:body [:maybe [:vector int?]] :parameters {:body [:maybe [:vector int?]]
:path [:map [:z int?]]} :path [:map [:z int?]]}
:openapi {:responses {400 {:description "kosh" :openapi {:responses {400 {:description "kosh"
:content {"application/json" {:schema {:type "string"}}}}}} :content {"application/json" {:schema {:type "string"}}}}}}
:responses {200 {:description "success" :responses {200 {:description "success"
:body [:map [:total int?]]} :body [:map [:total int?]]}
500 {:description "fail"}} 500 {:description "fail"}}
:handler (fn [{{{:keys [z]} :path :handler (fn [{{{:keys [z]} :path
xs :body} :parameters}] xs :body} :parameters}]
{:status 200, :body {:total (+ (reduce + xs) z)}})}}]] {:status 200, :body {:total (+ (reduce + xs) z)}})}}]]
["/schema" {:coercion schema/coercion} ["/schema" {:coercion schema/coercion}
["/plus/*z" ["/plus/*z"
{:get {:summary "plus" {:get {:summary "plus"
:tags [:plus :schema] :tags [:plus :schema]
:parameters {:query {:x s/Int, :y s/Int} :parameters {:query {:x s/Int, :y s/Int}
:path {:z s/Int}} :path {:z s/Int}}
:openapi {:responses {400 {:content {"application/json" {:schema {:type "string"}}} :openapi {:responses {400 {:content {"application/json" {:schema {:type "string"}}}
:description "kosh"}}} :description "kosh"}}}
:responses {200 {:description "success" :responses {200 {:description "success"
:body {:total s/Int}} :body {:total s/Int}}
500 {:description "fail"}} 500 {:description "fail"}}
:handler (fn [{{{:keys [x y]} :query :handler (fn [{{{:keys [x y]} :query
{:keys [z]} :path} :parameters}] {:keys [z]} :path} :parameters}]
{:status 200, :body {:total (+ x y z)}})} {:status 200, :body {:total (+ x y z)}})}
:post {:summary "plus with body" :post {:summary "plus with body"
:parameters {:body (s/maybe [s/Int]) :parameters {:body (s/maybe [s/Int])
:path {:z s/Int}} :path {:z s/Int}}
:openapi {:responses {400 {:content {"application/json" {:schema {:type "string"}}} :openapi {:responses {400 {:content {"application/json" {:schema {:type "string"}}}
:description "kosh"}}} :description "kosh"}}}
:responses {200 {:description "success" :responses {200 {:description "success"
:body {:total s/Int}} :body {:total s/Int}}
500 {:description "fail"}} 500 {:description "fail"}}
:handler (fn [{{{:keys [z]} :path :handler (fn [{{{:keys [z]} :path
xs :body} :parameters}] xs :body} :parameters}]
{:status 200, :body {:total (+ (reduce + xs) z)}})}}]]] {:status 200, :body {:total (+ (reduce + xs) z)}})}}]]]
{:validate reitit.ring.spec/validate {:validate reitit.ring.spec/validate
:data {:middleware [openapi/openapi-feature :data {:middleware [openapi/openapi-feature
rrc/coerce-exceptions-middleware rrc/coerce-exceptions-middleware
rrc/coerce-request-middleware rrc/coerce-request-middleware
rrc/coerce-response-middleware]}}))) rrc/coerce-response-middleware]}})))
(deftest openapi-test (deftest openapi-test
(testing "endpoints work" (testing "endpoints work"
@ -294,21 +294,21 @@
{:get {:no-doc true {:get {:no-doc true
:handler (openapi/create-openapi-handler)}}] :handler (openapi/create-openapi-handler)}}]
app (ring/ring-handler app (ring/ring-handler
(ring/router (ring/router
[["/common" {:openapi {:id #{::one ::two}}} [["/common" {:openapi {:id #{::one ::two}}}
ping-route] ping-route]
["/one" {:openapi {:id ::one}} ["/one" {:openapi {:id ::one}}
ping-route ping-route
spec-route] spec-route]
["/two" {:openapi {:id ::two}} ["/two" {:openapi {:id ::two}}
ping-route ping-route
spec-route spec-route
["/deep" {:openapi {:id ::one}} ["/deep" {:openapi {:id ::one}}
ping-route]] ping-route]]
["/one-two" {:openapi {:id #{::one ::two}}} ["/one-two" {:openapi {:id #{::one ::two}}}
spec-route]]))] spec-route]]))]
(is (= ["/common/ping" "/one/ping" "/two/deep/ping"] (is (= ["/common/ping" "/one/ping" "/two/deep/ping"]
(spec-paths app "/one/openapi.json"))) (spec-paths app "/one/openapi.json")))
(is (= ["/common/ping" "/two/ping"] (is (= ["/common/ping" "/two/ping"]
@ -318,9 +318,9 @@
(deftest openapi-ui-config-test (deftest openapi-ui-config-test
(let [app (swagger-ui/create-swagger-ui-handler (let [app (swagger-ui/create-swagger-ui-handler
{:path "/" {:path "/"
:url "/openapi.json" :url "/openapi.json"
:config {:jsonEditor true}})] :config {:jsonEditor true}})]
(is (= 302 (:status (app {:request-method :get, :uri "/"})))) (is (= 302 (:status (app {:request-method :get, :uri "/"}))))
(is (= 200 (:status (app {:request-method :get, :uri "/index.html"})))) (is (= 200 (:status (app {:request-method :get, :uri "/index.html"}))))
(is (= {:jsonEditor true, :url "/openapi.json"} (is (= {:jsonEditor true, :url "/openapi.json"}
@ -329,12 +329,12 @@
(deftest without-openapi-id-test (deftest without-openapi-id-test
(let [app (ring/ring-handler (let [app (ring/ring-handler
(ring/router (ring/router
[["/ping" [["/ping"
{:get (constantly "ping")}] {:get (constantly "ping")}]
["/openapi.json" ["/openapi.json"
{:get {:no-doc true {:get {:no-doc true
:handler (openapi/create-openapi-handler)}}]]))] :handler (openapi/create-openapi-handler)}}]]))]
(is (= ["/ping"] (spec-paths app "/openapi.json"))) (is (= ["/ping"] (spec-paths app "/openapi.json")))
(is (= #{::openapi/default} (is (= #{::openapi/default}
(-> {:request-method :get :uri "/openapi.json"} (-> {:request-method :get :uri "/openapi.json"}
@ -342,14 +342,14 @@
(deftest with-options-endpoint-test (deftest with-options-endpoint-test
(let [app (ring/ring-handler (let [app (ring/ring-handler
(ring/router (ring/router
[["/ping" [["/ping"
{:options (constantly "options")}] {:options (constantly "options")}]
["/pong" ["/pong"
(constantly "options")] (constantly "options")]
["/openapi.json" ["/openapi.json"
{:get {:no-doc true {:get {:no-doc true
:handler (openapi/create-openapi-handler)}}]]))] :handler (openapi/create-openapi-handler)}}]]))]
(is (= ["/ping" "/pong"] (spec-paths app "/openapi.json"))) (is (= ["/ping" "/pong"] (spec-paths app "/openapi.json")))
(is (= #{::openapi/default} (is (= #{::openapi/default}
(-> {:request-method :get :uri "/openapi.json"} (-> {:request-method :get :uri "/openapi.json"}
@ -370,7 +370,7 @@
{:description (str "description " nom)})})] {:description (str "description " nom)})})]
[#'spec/coercion (fn [nom] {nom (st/spec {:spec string? [#'spec/coercion (fn [nom] {nom (st/spec {:spec string?
:description (str "description " nom)})})]]] :description (str "description " nom)})})]]]
(testing coercion (testing (str coercion)
(let [app (ring/ring-handler (let [app (ring/ring-handler
(ring/router (ring/router
[["/parameters" [["/parameters"
@ -414,9 +414,9 @@
:required true :required true
:description "description :p" :description "description :p"
:schema {:type "string"}}] :schema {:type "string"}}]
(-> spec (-> spec
(get-in [:paths "/parameters" :post :parameters]) (get-in [:paths "/parameters" :post :parameters])
normalize)))) normalize))))
(testing "body parameter" (testing "body parameter"
(is (match? (merge {:type "object" (is (match? (merge {:type "object"
:properties {:b {:type "string"}} :properties {:b {:type "string"}}
@ -449,9 +449,9 @@
{:openapi/example {nom "EXAMPLE2"}}))] {:openapi/example {nom "EXAMPLE2"}}))]
[#'spec/coercion (fn [nom] [#'spec/coercion (fn [nom]
(assoc (assoc
(ds/spec ::foo {nom (st/spec string? {:openapi/example "EXAMPLE"})}) (ds/spec ::foo {nom (st/spec string? {:openapi/example "EXAMPLE"})})
:openapi/example {nom "EXAMPLE2"}))]]] :openapi/example {nom "EXAMPLE2"}))]]]
(testing coercion (testing (str coercion)
(let [app (ring/ring-handler (let [app (ring/ring-handler
(ring/router (ring/router
[["/examples" [["/examples"
@ -489,9 +489,9 @@
:required true :required true
:schema {:type "string" :schema {:type "string"
:example "EXAMPLE"}}] :example "EXAMPLE"}}]
(-> spec (-> spec
(get-in [:paths "/examples" :post :parameters]) (get-in [:paths "/examples" :post :parameters])
normalize)))) normalize))))
(testing "body parameter" (testing "body parameter"
(is (match? {:schema {:type "object" (is (match? {:schema {:type "object"
:properties {:b {:type "string" :properties {:b {:type "string"
@ -531,7 +531,7 @@
[#'spec/coercion [#'spec/coercion
reitit.http.interceptors.multipart/bytes-part reitit.http.interceptors.multipart/bytes-part
string?]]] string?]]]
(testing coercion (testing (str coercion)
(let [app (ring/ring-handler (let [app (ring/ring-handler
(ring/router (ring/router
[["/upload" [["/upload"
@ -569,7 +569,7 @@
[[#'malli/coercion (fn [nom] [:map [nom :string]])] [[#'malli/coercion (fn [nom] [:map [nom :string]])]
[#'schema/coercion (fn [nom] {nom s/Str})] [#'schema/coercion (fn [nom] {nom s/Str})]
[#'spec/coercion (fn [nom] {nom string?})]]] [#'spec/coercion (fn [nom] {nom string?})]]]
(testing coercion (testing (str coercion)
(let [app (ring/ring-handler (let [app (ring/ring-handler
(ring/router (ring/router
[["/parameters" [["/parameters"

View file

@ -114,7 +114,6 @@
rrc/coerce-request-middleware rrc/coerce-request-middleware
rrc/coerce-response-middleware]}}))) rrc/coerce-response-middleware]}})))
(require '[fipp.edn])
(deftest swagger-test (deftest swagger-test
(testing "endpoints work" (testing "endpoints work"
(testing "spec" (testing "spec"
@ -430,7 +429,7 @@
[#'spec/coercion [#'spec/coercion
reitit.http.interceptors.multipart/bytes-part reitit.http.interceptors.multipart/bytes-part
string?]]] string?]]]
(testing coercion (testing (str coercion)
(let [app (ring/ring-handler (let [app (ring/ring-handler
(ring/router (ring/router
[["/upload" [["/upload"