diff --git a/modules/reitit-core/src/reitit/coercion.cljc b/modules/reitit-core/src/reitit/coercion.cljc index ad96102b..4266fea9 100644 --- a/modules/reitit-core/src/reitit/coercion.cljc +++ b/modules/reitit-core/src/reitit/coercion.cljc @@ -184,8 +184,8 @@ (defn response-coercers [coercion responses opts] (some->> (for [[status model] responses] (do - (when-not (int? status) - (throw (ex-info "Response status must be int" {:status status}))) + (when-not (or (= :default status) (int? status)) + (throw (ex-info "Response status must be int or :default" {:status status}))) [status (response-coercer coercion model opts)])) (filter second) (seq) (into {}))) diff --git a/test/cljc/reitit/openapi_test.clj b/test/cljc/reitit/openapi_test.clj index c474fbf3..3e0f85b4 100644 --- a/test/cljc/reitit/openapi_test.clj +++ b/test/cljc/reitit/openapi_test.clj @@ -67,9 +67,9 @@ :responses {200 {:description "success" :body {:total int?}} 500 {:description "fail"} - 504 {:description "default" - :content {:default {:schema {:error string?}}} - :body {:masked string?}}} + :default {:description "default" + :content {:default {:schema {:error string?}}} + :body {:masked string?}}} :handler (fn [{{{:keys [z]} :path xs :body} :parameters}] {:status 200, :body {:total (+ (reduce + xs) z)}})}}]] @@ -96,9 +96,9 @@ :responses {200 {:description "success" :body [:map [:total int?]]} 500 {:description "fail"} - 504 {:description "default" - :content {:default {:schema {:error string?}}} - :body {:masked string?}}} + :default {:description "default" + :content {:default {:schema {:error string?}}} + :body {:masked string?}}} :handler (fn [{{{:keys [z]} :path xs :body} :parameters}] {:status 200, :body {:total (+ (reduce + xs) z)}})}}]] @@ -125,9 +125,9 @@ :responses {200 {:description "success" :body {:total s/Int}} 500 {:description "fail"} - 504 {:description "default" - :content {:default {:schema {:error s/Str}}} - :body {:masked s/Str}}} + :default {:description "default" + :content {:default {:schema {:error s/Str}}} + :body {:masked s/Str}}} :handler (fn [{{{:keys [z]} :path xs :body} :parameters}] {:status 200, :body {:total (+ (reduce + xs) z)}})}}]]] @@ -200,10 +200,10 @@ 400 {:content {"application/json" {:schema {:type "string"}}} :description "kosh"} 500 {:description "fail"} - 504 {:description "default" - :content {"application/json" {:schema {:properties {"error" {:type "string"}} - :required ["error"] - :type "object"}}}}} + :default {:description "default" + :content {"application/json" {:schema {:properties {"error" {:type "string"}} + :required ["error"] + :type "object"}}}}} :summary "plus with body"}} "/api/malli/plus/{z}" {:get {:parameters [{:in "query" :name :x @@ -242,11 +242,11 @@ 400 {:description "kosh" :content {"application/json" {:schema {:type "string"}}}} 500 {:description "fail"} - 504 {:description "default" - :content {"application/json" {:schema {:additionalProperties false - :properties {:error {:type "string"}} - :required [:error] - :type "object"}}}}} + :default {:description "default" + :content {"application/json" {:schema {:additionalProperties false + :properties {:error {:type "string"}} + :required [:error] + :type "object"}}}}} :summary "plus with body"}} "/api/schema/plus/{z}" {:get {:parameters [{:in "query" :name "x" @@ -292,11 +292,11 @@ 400 {:description "kosh" :content {"application/json" {:schema {:type "string"}}}} 500 {:description "fail"} - 504 {:description "default" - :content {"application/json" {:schema {:additionalProperties false - :properties {"error" {:type "string"}} - :required ["error"] - :type "object"}}}}} + :default {:description "default" + :content {"application/json" {:schema {:additionalProperties false + :properties {"error" {:type "string"}} + :required ["error"] + :type "object"}}}}} :summary "plus with body"}}}}] (is (= expected spec)) (is (= nil (validate spec)))))) diff --git a/test/cljc/reitit/ring_coercion_test.cljc b/test/cljc/reitit/ring_coercion_test.cljc index 91fa5135..3c93cae9 100644 --- a/test/cljc/reitit/ring_coercion_test.cljc +++ b/test/cljc/reitit/ring_coercion_test.cljc @@ -680,6 +680,62 @@ (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 (deftest muuntaja-test (let [app (ring/ring-handler