mirror of
https://github.com/metosin/reitit.git
synced 2025-12-18 08:51:12 +00:00
feat: allow :default response status code again
it is an old feature, but didn't have a test, so it was broken by #715 also add a test so we don't break it again
This commit is contained in:
parent
78cf477b88
commit
dd835e73a8
3 changed files with 81 additions and 25 deletions
|
|
@ -184,8 +184,8 @@
|
||||||
(defn response-coercers [coercion responses opts]
|
(defn response-coercers [coercion responses opts]
|
||||||
(some->> (for [[status model] responses]
|
(some->> (for [[status model] responses]
|
||||||
(do
|
(do
|
||||||
(when-not (int? status)
|
(when-not (or (= :default status) (int? status))
|
||||||
(throw (ex-info "Response status must be int" {:status status})))
|
(throw (ex-info "Response status must be int or :default" {:status status})))
|
||||||
[status (response-coercer coercion model opts)]))
|
[status (response-coercer coercion model opts)]))
|
||||||
(filter second) (seq) (into {})))
|
(filter second) (seq) (into {})))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -67,9 +67,9 @@
|
||||||
:responses {200 {:description "success"
|
:responses {200 {:description "success"
|
||||||
:body {:total int?}}
|
:body {:total int?}}
|
||||||
500 {:description "fail"}
|
500 {:description "fail"}
|
||||||
504 {:description "default"
|
:default {:description "default"
|
||||||
:content {:default {:schema {:error string?}}}
|
:content {:default {:schema {:error string?}}}
|
||||||
:body {:masked string?}}}
|
:body {:masked string?}}}
|
||||||
: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)}})}}]]
|
||||||
|
|
@ -96,9 +96,9 @@
|
||||||
:responses {200 {:description "success"
|
:responses {200 {:description "success"
|
||||||
:body [:map [:total int?]]}
|
:body [:map [:total int?]]}
|
||||||
500 {:description "fail"}
|
500 {:description "fail"}
|
||||||
504 {:description "default"
|
:default {:description "default"
|
||||||
:content {:default {:schema {:error string?}}}
|
:content {:default {:schema {:error string?}}}
|
||||||
:body {:masked string?}}}
|
:body {:masked string?}}}
|
||||||
: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)}})}}]]
|
||||||
|
|
@ -125,9 +125,9 @@
|
||||||
:responses {200 {:description "success"
|
:responses {200 {:description "success"
|
||||||
:body {:total s/Int}}
|
:body {:total s/Int}}
|
||||||
500 {:description "fail"}
|
500 {:description "fail"}
|
||||||
504 {:description "default"
|
:default {:description "default"
|
||||||
:content {:default {:schema {:error s/Str}}}
|
:content {:default {:schema {:error s/Str}}}
|
||||||
:body {:masked s/Str}}}
|
:body {:masked s/Str}}}
|
||||||
: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)}})}}]]]
|
||||||
|
|
@ -200,10 +200,10 @@
|
||||||
400 {:content {"application/json" {:schema {:type "string"}}}
|
400 {:content {"application/json" {:schema {:type "string"}}}
|
||||||
:description "kosh"}
|
:description "kosh"}
|
||||||
500 {:description "fail"}
|
500 {:description "fail"}
|
||||||
504 {:description "default"
|
:default {:description "default"
|
||||||
:content {"application/json" {:schema {:properties {"error" {:type "string"}}
|
:content {"application/json" {:schema {:properties {"error" {:type "string"}}
|
||||||
:required ["error"]
|
:required ["error"]
|
||||||
:type "object"}}}}}
|
:type "object"}}}}}
|
||||||
:summary "plus with body"}}
|
:summary "plus with body"}}
|
||||||
"/api/malli/plus/{z}" {:get {:parameters [{:in "query"
|
"/api/malli/plus/{z}" {:get {:parameters [{:in "query"
|
||||||
:name :x
|
:name :x
|
||||||
|
|
@ -242,11 +242,11 @@
|
||||||
400 {:description "kosh"
|
400 {:description "kosh"
|
||||||
:content {"application/json" {:schema {:type "string"}}}}
|
:content {"application/json" {:schema {:type "string"}}}}
|
||||||
500 {:description "fail"}
|
500 {:description "fail"}
|
||||||
504 {:description "default"
|
:default {:description "default"
|
||||||
:content {"application/json" {:schema {:additionalProperties false
|
:content {"application/json" {:schema {:additionalProperties false
|
||||||
:properties {:error {:type "string"}}
|
:properties {:error {:type "string"}}
|
||||||
:required [:error]
|
:required [:error]
|
||||||
:type "object"}}}}}
|
:type "object"}}}}}
|
||||||
:summary "plus with body"}}
|
:summary "plus with body"}}
|
||||||
"/api/schema/plus/{z}" {:get {:parameters [{:in "query"
|
"/api/schema/plus/{z}" {:get {:parameters [{:in "query"
|
||||||
:name "x"
|
:name "x"
|
||||||
|
|
@ -292,11 +292,11 @@
|
||||||
400 {:description "kosh"
|
400 {:description "kosh"
|
||||||
:content {"application/json" {:schema {:type "string"}}}}
|
:content {"application/json" {:schema {:type "string"}}}}
|
||||||
500 {:description "fail"}
|
500 {:description "fail"}
|
||||||
504 {:description "default"
|
:default {:description "default"
|
||||||
:content {"application/json" {:schema {:additionalProperties false
|
:content {"application/json" {:schema {:additionalProperties false
|
||||||
:properties {"error" {:type "string"}}
|
:properties {"error" {:type "string"}}
|
||||||
:required ["error"]
|
:required ["error"]
|
||||||
:type "object"}}}}}
|
:type "object"}}}}}
|
||||||
:summary "plus with body"}}}}]
|
:summary "plus with body"}}}}]
|
||||||
(is (= expected spec))
|
(is (= expected spec))
|
||||||
(is (= nil (validate spec))))))
|
(is (= nil (validate spec))))))
|
||||||
|
|
|
||||||
|
|
@ -680,6 +680,62 @@
|
||||||
(call (request "application/json" "application/transit" {:request :json :response :json}))))))))))))
|
(call (request "application/json" "application/transit" {:request :json :response :json}))))))))))))
|
||||||
|
|
||||||
|
|
||||||
|
#?(:clj
|
||||||
|
(deftest response-coercion-test
|
||||||
|
(doseq [[coercion schema-200 schema-default]
|
||||||
|
[[malli/coercion
|
||||||
|
[:map [:a :int]]
|
||||||
|
[:map [:b :int]]]
|
||||||
|
[schema/coercion
|
||||||
|
{:a s/Int}
|
||||||
|
{:b s/Int}]
|
||||||
|
[spec/coercion
|
||||||
|
{:a int?}
|
||||||
|
{:b int?}]]]
|
||||||
|
(testing (str coercion)
|
||||||
|
(let [app (ring/ring-handler
|
||||||
|
(ring/router
|
||||||
|
["/foo" {:post {:responses {200 {:content {:default {:schema schema-200}}}
|
||||||
|
:default {:content {"application/json" {:schema schema-default}}}}
|
||||||
|
:handler (fn [req]
|
||||||
|
{:status (-> req :body-params :status)
|
||||||
|
:body (-> req :body-params :response)})}}]
|
||||||
|
{:validate reitit.ring.spec/validate
|
||||||
|
:data {:middleware [rrc/coerce-request-middleware
|
||||||
|
rrc/coerce-response-middleware]
|
||||||
|
:coercion coercion}}))
|
||||||
|
call (fn [request]
|
||||||
|
(try
|
||||||
|
(app request)
|
||||||
|
(catch ExceptionInfo e
|
||||||
|
(select-keys (ex-data e) [:type :in]))))
|
||||||
|
request (fn [body]
|
||||||
|
{:request-method :post
|
||||||
|
:uri "/foo"
|
||||||
|
:muuntaja/request {:format "application/json"}
|
||||||
|
:muuntaja/response {:format (:format body "application/json")}
|
||||||
|
:body-params body})]
|
||||||
|
(testing "explicit response schema"
|
||||||
|
(is (= {:status 200 :body {:a 1}}
|
||||||
|
(call (request {:status 200 :response {:a 1}})))
|
||||||
|
"valid response")
|
||||||
|
(is (= {:type :reitit.coercion/response-coercion, :in [:response :body]}
|
||||||
|
(call (request {:status 200 :response {:b 1}})))
|
||||||
|
"invalid response")
|
||||||
|
(is (= {:type :reitit.coercion/response-coercion, :in [:response :body]}
|
||||||
|
(call (request {:status 200 :response {:b 1} :format "application/edn"})))
|
||||||
|
"invalid response, different content-type"))
|
||||||
|
(testing "default response schema"
|
||||||
|
(is (= {:status 300 :body {:b 2}}
|
||||||
|
(call (request {:status 300 :response {:b 2}})))
|
||||||
|
"valid response")
|
||||||
|
(is (= {:type :reitit.coercion/response-coercion, :in [:response :body]}
|
||||||
|
(call (request {:status 300 :response {:a 2}})))
|
||||||
|
"invalid response")
|
||||||
|
(is (= {:status 300 :body "anything goes!"}
|
||||||
|
(call (request {:status 300 :response "anything goes!" :format "application/edn"})))
|
||||||
|
"no coercion applied due to content-type")))))))
|
||||||
|
|
||||||
#?(:clj
|
#?(:clj
|
||||||
(deftest muuntaja-test
|
(deftest muuntaja-test
|
||||||
(let [app (ring/ring-handler
|
(let [app (ring/ring-handler
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue