diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b5aeb21..a2392d1c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,19 @@ +## UNRELEASED + +Support `:-` in the `:query`, `:body` and `:headers`, e.g. the following are equivalent: + +```clj +(POST "/user" [] + :return User + :body [user User] + (ok user)) + +(POST "/user" [] + :return User + :body [user :- User] + (ok user)) +``` + ## 2.0.0-alpha15 * updated deps: diff --git a/src/compojure/api/meta.clj b/src/compojure/api/meta.clj index a5e7b6ce..d53b7e37 100644 --- a/src/compojure/api/meta.clj +++ b/src/compojure/api/meta.clj @@ -59,6 +59,19 @@ {200 {:schema schema :description (or (js/json-schema-meta schema) "")}}) +(defn value-and-schema [[value schema ?schema :as binding]] + (cond + ;; [body :- {:a s/Int}] + (and ?schema (= :- schema)) + [value ?schema] + + ;; [body {:a s/Int}] + (not ?schema) + [value schema] + + :else + (throw (ex-info (str "bad let-binding syntax: " binding) {})))) + ;; ;; Extension point ;; @@ -305,12 +318,17 @@ (help/code "(POST \"/echo\" []" " :body [body User]" + " (ok body))" + "" + "(POST \"/echo\" []" + " :body [body :- User]" " (ok body))"))) -(defmethod restructure-param :body [_ [value schema] acc] - (-> acc - (update-in [:lets] into [value (src-coerce! schema :body-params :body false)]) - (assoc-in [:info :public :parameters :body] schema))) +(defmethod restructure-param :body [_ binding acc] + (let [[value schema] (value-and-schema binding)] + (-> acc + (update-in [:lets] into [value (src-coerce! schema :body-params :body false)]) + (assoc-in [:info :public :parameters :body] schema)))) ;; ;; query @@ -323,12 +341,17 @@ (help/code "(GET \"/search\" []" " :query [params {:q s/Str, :max s/Int}]" + " (ok params))" + "" + "(GET \"/search\" []" + " :query [params :- {:q s/Str, :max s/Int}]" " (ok params))"))) -(defmethod restructure-param :query [_ [value schema] acc] - (-> acc - (update-in [:lets] into [value (src-coerce! schema :query-params :string)]) - (assoc-in [:info :public :parameters :query] schema))) +(defmethod restructure-param :query [_ binding acc] + (let [[value schema] (value-and-schema binding)] + (-> acc + (update-in [:lets] into [value (src-coerce! schema :query-params :string)]) + (assoc-in [:info :public :parameters :query] schema)))) ;; ;; headers @@ -341,12 +364,17 @@ (help/code "(GET \"/headers\" []" " :headers [headers HeaderSchema]" + " (ok headers))" + "" + "(GET \"/headers\" []" + " :headers [headers :- HeaderSchema]" " (ok headers))"))) -(defmethod restructure-param :headers [_ [value schema] acc] - (-> acc - (update-in [:lets] into [value (src-coerce! schema :headers :string)]) - (assoc-in [:info :public :parameters :header] schema))) +(defmethod restructure-param :headers [_ binding acc] + (let [[value schema] (value-and-schema binding)] + (-> acc + (update-in [:lets] into [value (src-coerce! schema :headers :string)]) + (assoc-in [:info :public :parameters :header] schema)))) ;; ;; body-params diff --git a/test/compojure/api/integration_test.clj b/test/compojure/api/integration_test.clj index 9dcd412a..505c2e35 100644 --- a/test/compojure/api/integration_test.clj +++ b/test/compojure/api/integration_test.clj @@ -202,6 +202,10 @@ :return User :query [user User] (ok user)) + (GET "/user2" [] + :return User + :query [user :- User] + (ok user)) (GET "/invalid-user" [] :return User (ok invalid-user)) @@ -211,6 +215,10 @@ :return User :body [user User] (ok user)) + (POST "/user2" [] + :return User + :body [user User] + (ok user)) (POST "/user_list" [] :return [User] :body [users [User]] @@ -223,6 +231,10 @@ :return User :headers [user UserHeaders] (ok (select-keys user [:id :name]))) + (POST "/user_headers2" [] + :return User + :headers [user :- UserHeaders] + (ok (select-keys user [:id :name]))) (POST "/user_legacy" {user :body-params} :return User (ok user))))] @@ -237,11 +249,21 @@ status => 200 body => pertti)) + (fact "GET with smart destructuring & :-" + (let [[status body] (get* app "/models/user2" pertti)] + status => 200 + body => pertti)) + (fact "POST with smart destructuring" (let [[status body] (post* app "/models/user" (json-string pertti))] status => 200 body => pertti)) + (fact "POST with smart destructuring & :-" + (let [[status body] (post* app "/models/user2" (json-string pertti))] + status => 200 + body => pertti)) + (fact "POST with smart destructuring - lists" (let [[status body] (post* app "/models/user_list" (json-string [pertti]))] status => 200 @@ -262,6 +284,11 @@ status => 200 body => pertti)) + (fact "POST with smart destructuring - headers & :-" + (let [[status body] (headers-post* app "/models/user_headers2" pertti)] + status => 200 + body => pertti)) + (fact "Validation of returned data" (let [[status] (get* app "/models/invalid-user")] status => 500))