Skip to content

Commit

Permalink
require explicit muuntaja config
Browse files Browse the repository at this point in the history
  • Loading branch information
frenchy64 committed May 1, 2024
1 parent 9896e46 commit 7cb1cbc
Show file tree
Hide file tree
Showing 14 changed files with 240 additions and 62 deletions.
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
See also: [compojure-api 1.1.x changelog](./CHANGELOG-1.1.x.md)

## NEXT
## 2.0.0-alpha34-SNAPSHOT
* **BREAKING CHANGE**: `:formatter :muuntaja` sometimes required for `api{-middleware}` options
* to prepare for 1.x compatibility, :muuntaja must be explicitly configured
* Migration instructions: run your program and fix the error messages, which will provide specific instructions.
* to circumvent this change, set `-Dcompojure.api.middleware.global-default-formatter=:muuntaja`
* stable 2.x will default `:formatter` to `:ring-middleware-format`

## 2.0.0-alpha33 (2024-04-30)
* Throw an error on malformed `:{body,query,headers}`, in particular if anything other than 2 elements was provided
Expand Down
3 changes: 2 additions & 1 deletion examples/thingie/src/examples/thingie.clj
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@

(def app
(api
{:swagger
{:formatter :muuntaja
:swagger
{:ui "/"
:spec "/swagger.json"
:data {:info {:version "1.0.0"
Expand Down
18 changes: 17 additions & 1 deletion src/compojure/api/api.clj
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,21 @@
api
[& body]
(let [[options handlers] (common/extract-parameters body false)
_ (assert (not (contains? options :format))
(str "ERROR: Option [:format] is not used with 2.* version.\n"
"Compojure-api uses now Muuntaja insted of ring-middleware-format,\n"
"the new formatting options for it should be under [:formats]. See\n"
"[[api-middleware]] documentation for more details.\n"))
_ (when (and (not (:formatter options))
(not (contains? options :formats))
(not (System/getProperty "compojure.api.middleware.global-default-formatter")))
(throw (ex-info (str "ERROR: Please set `:formatter :muuntaja` in the options map of `api`.\n"
"e.g., (api {:formatter :muuntaja} routes...)\n"
"To prepare for backwards compatibility with compojure-api 1.x, the formatting library must be\n"
"explicitly chosen if not configured by `:format` (ring-middleware-format) or \n"
"`:formats` (muuntaja). Once 2.x is stable, the default will be `:formatter :ring-middleware-format`.\n"
"To globally override the formatter, use -Dcompojure.api.middleware.global-default-formatter=:muuntaja")
{})))
options (rsc/deep-merge api-defaults options)
handler (apply c/routes (concat [(swagger/swagger-routes (:swagger options))] handlers))
partial-api-route (routes/map->Route
Expand All @@ -63,7 +78,8 @@
lookup (routes/route-lookup-table routes)
swagger-data (get-in options [:swagger :data])
enable-api-middleware? (not (get-in options [:api :disable-api-middleware?]))
api-middleware-options (mw/api-middleware-options (dissoc options :api :swagger))
api-middleware-options (dissoc (mw/api-middleware-options (assoc (dissoc options :api :swagger) ::via-api true))
::mw/api-middleware-defaults)
api-handler (-> handler
(cond-> swagger-data (rsm/wrap-swagger-data swagger-data))
(cond-> enable-api-middleware? (mw/api-middleware
Expand Down
46 changes: 44 additions & 2 deletions src/compojure/api/middleware.clj
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,8 @@
;;

(def api-middleware-defaults
{:formats ::default
{::api-middleware-defaults true
:formats ::default
:exceptions {:handlers {:ring.util.http-response/response ex/http-response-handler
::ex/request-validation ex/request-validation-handler
::ex/request-parsing ex/request-parsing-handler
Expand Down Expand Up @@ -234,6 +235,15 @@
### Options
- **:formatter** either :ring-middleware-format or :muuntaja.
During 2.x pre-releases, this will be a required key, unless
:formats is provided, which is equivalent to setting to :muuntaja.
Stable 2.x releases will default to :ring-middleware-format if
not provided or :format is set, unless :formats is provided,
which is equivalent to setting to :muuntaja.
Stable 2.x will print a deprecation warning if implicitly
or explicitly set to :ring-middleware-format.
- **:exceptions** for *compojure.api.middleware/wrap-exceptions* (nil to unmount it)
- **:handlers** Map of error handlers for different exception types, type refers to `:type` key in ExceptionInfo data.
Expand All @@ -256,9 +266,41 @@
you might want to take look at using wrap-components
middleware manually.). Defaults to nil (middleware not mounted)."
([handler]
(throw (ex-info (str "ERROR: Please set `:formatter :muuntaja` in the options map of `api-middleware.\n"
"e.g., (api-middleware <handler> {:formatter :muuntaja})\n"
"To prepare for backwards compatibility with compojure-api 1.x, the formatting library must be \n"
"explicitly chosen if not configured by `:format` (ring-middleware-format) or\n"
"`:formats` (muuntaja). Once 2.x is stable, the default will be `:formatter :ring-middleware-format`.")
{}))
(api-middleware handler api-middleware-defaults))
([handler options]
(let [options (api-middleware-options options)
(when (and (::api-middleware-defaults options)
(not (:formatter options))
(not (System/getProperty "compojure.api.middleware.global-default-formatter")))
(throw (ex-info (str "ERROR: Please set `:formatter :muuntaja` in the options map of `api-middleware.\n"
"e.g., (api-middleware <handler> {:formatter :muuntaja})\n"
"To prepare for backwards compatibility with compojure-api 1.x, the formatting library must be\n"
"explicitly chosen if not configured by `:format` (ring-middleware-format) or\n"
":formats (muuntaja). Once 2.x is stable, the default will be `:formatter :ring-middleware-format`.\n"
"To globally override the default formatter, use -Dcompojure.api.middleware.global-default-formatter=:muuntaja")
{})))
(let [formatter (or (:formatter options)
(when (or (contains? options :formats)
(= (System/getProperty "compojure.api.middleware.global-default-formatter")
":muuntaja"))
:muuntaja)
(throw (ex-info (str "ERROR: Please set `:formatter :muuntaja` in the options map of `api-middleware.\n"
"e.g., (api-middleware <handler> {:formatter :muuntaja})\n"
"To prepare for backwards compatibility with compojure-api 1.x, the formatting library must be\n"
"explicitly chosen if not configured by `:format` (ring-middleware-format) or\n"
":formats (muuntaja). Once 2.x is stable, the default will be `:formatter :ring-middleware-format`.\n"
"To globally override the default formatter, use -Dcompojure.api.middleware.global-default-formatter=:muuntaja")
{}))
;; TODO 2.x stable
:ring-middleware-format)
_ (assert (= :muuntaja formatter)
(str "Invalid :formatter: " (pr-str formatter) ". Must be :muuntaja."))
options (api-middleware-options options)
{:keys [exceptions components formats middleware ring-swagger coercion]} options
muuntaja (create-muuntaja formats)]

Expand Down
3 changes: 2 additions & 1 deletion test/compojure/api/coercion/schema_coercion_test.clj
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,8 @@

(deftest apis-test
(let [app (api
{:swagger {:spec "/swagger.json"}
{:formatter :muuntaja
:swagger {:spec "/swagger.json"}
:coercion :schema}

(POST "/body" []
Expand Down
47 changes: 31 additions & 16 deletions test/compojure/api/coercion_test.clj
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,11 @@
:default {:schema {:value s/Int}}}
(ok {:value (or value "123")}))]
(testing "200"
(is-has-body {:value "123"} (get* (api r-200) "/"))
(is-fails-with 500 (get* (api r-200) "/" {:value 123})))
(is-has-body {:value "123"} (get* (api {:formatter :muuntaja} r-200) "/"))
(is-fails-with 500 (get* (api {:formatter :muuntaja} r-200) "/" {:value 123})))

(testing "exception data"
(let [ex (get* (api r-200) "/" {:value 123})]
(let [ex (get* (api {:formatter :muuntaja} r-200) "/" {:value 123})]
(is (= 500 (first ex)))
(is (= {:type "compojure.api.exception/response-validation"
:coercion "schema",
Expand All @@ -46,12 +46,12 @@
(select-keys (second ex) [:type :coercion :in :value :schema :errors])))))

(testing ":default"
(is-has-body {:value "123"} (get* (api r-default) "/"))
(is-fails-with 500 (get* (api r-default) "/" {:value 123})))
(is-has-body {:value "123"} (get* (api {:formatter :muuntaja} r-default) "/"))
(is-fails-with 500 (get* (api {:formatter :muuntaja} r-default) "/" {:value 123})))

(testing ":default"
(is-has-body {:value "123"} (get* (api r-200-default) "/"))
(is-fails-with 500 (get* (api r-200-default) "/" {:value 123})))))
(is-has-body {:value "123"} (get* (api {:formatter :muuntaja} r-200-default) "/"))
(is-fails-with 500 (get* (api {:formatter :muuntaja} r-200-default) "/" {:value 123})))))

(testing "custom coercion"

Expand All @@ -62,20 +62,23 @@

(testing "by default, applies response coercion"
(let [app (api
{:formatter :muuntaja}
ping-route)]
(is-fails-with 500 (get* app "/ping"))))

(testing "response-coercion can be disabled"
(testing "separately"
(let [app (api
{:coercion (cs/create-coercion (dissoc cs/default-options :response))}
{:formatter :muuntaja
:coercion (cs/create-coercion (dissoc cs/default-options :response))}
ping-route)]
(let [[status body] (get* app "/ping")]
(is (= 200 status))
(is (= {:pong 123} body)))))
(testing "all coercion"
(let [app (api
{:coercion nil}
{:formatter :muuntaja
:coercion nil}
ping-route)]
(let [[status body] (get* app "/ping")]
(is (= 200 status))
Expand All @@ -84,12 +87,16 @@
(testing "coercion for async handlers"
(binding [*async?* true]
(testing "successful"
(let [app (api (GET "/async" []
(let [app (api
{:formatter :muuntaja}
(GET "/async" []
:return s/Str
(a/go (ok "abc"))))]
(is-has-body "abc" (get* app "/async"))))
(testing "failing"
(let [app (api (GET "/async" []
(let [app (api
{:formatter :muuntaja}
(GET "/async" []
:return s/Int
(a/go (ok "foo"))))]
(is-fails-with 500 (get* app "/async"))))))))
Expand All @@ -101,6 +108,7 @@

(testing "by default, applies body coercion (to set)"
(let [app (api
{:formatter :muuntaja}
beer-route)]
(let [[status body] (post* app "/beer" (json-string {:beers ["ipa" "apa" "ipa"]}))]
(is (= 200 status))
Expand All @@ -109,13 +117,15 @@
(testing "body-coercion can be disabled"
(let [no-body-coercion (cs/create-coercion (dissoc cs/default-options :body))
app (api
{:coercion no-body-coercion}
{:formatter :muuntaja
:coercion no-body-coercion}
beer-route)]
(let [[status body] (post* app "/beer" (json-string {:beers ["ipa" "apa" "ipa"]}))]
(is (= 200 status))
(is (= {:beers ["ipa" "apa" "ipa"]} body))))
(let [app (api
{:coercion nil}
{:formatter :muuntaja
:coercion nil}
beer-route)]
(let [[status body] (post* app "/beer" (json-string {:beers ["ipa" "apa" "ipa"]}))]
(is (= 200 status))
Expand All @@ -124,7 +134,8 @@
(testing "body-coercion can be changed"
(let [nop-body-coercion (cs/create-coercion (assoc cs/default-options :body {:default (constantly nil)}))
app (api
{:coercion nop-body-coercion}
{:formatter :muuntaja
:coercion nop-body-coercion}
beer-route)]
(is-fails-with 400 (post* app "/beer" (json-string {:beers ["ipa" "apa" "ipa"]})))))))

Expand All @@ -135,6 +146,7 @@

(testing "by default, applies query coercion (string->int)"
(let [app (api
{:formatter :muuntaja}
query-route)]
(let [[status body] (get* app "/query" {:i 10})]
(is (= 200 status))
Expand All @@ -143,7 +155,8 @@
(testing "query-coercion can be disabled"
(let [no-query-coercion (cs/create-coercion (dissoc cs/default-options :string))
app (api
{:coercion no-query-coercion}
{:formatter :muuntaja
:coercion no-query-coercion}
query-route)]
(let [[status body] (get* app "/query" {:i 10})]
(is (= 200 status))
Expand All @@ -152,12 +165,14 @@
(testing "query-coercion can be changed"
(let [nop-query-coercion (cs/create-coercion (assoc cs/default-options :string {:default (constantly nil)}))
app (api
{:coercion nop-query-coercion}
{:formatter :muuntaja
:coercion nop-query-coercion}
query-route)]
(is-fails-with 400 (get* app "/query" {:i 10}))))))

(testing "route-specific coercion"
(let [app (api
{:formatter :muuntaja}
(GET "/default" []
:query-params [i :- s/Int]
(ok {:i i}))
Expand Down
Loading

0 comments on commit 7cb1cbc

Please sign in to comment.