Skip to content

Commit 7cb1cbc

Browse files
committed
require explicit muuntaja config
1 parent 9896e46 commit 7cb1cbc

File tree

14 files changed

+240
-62
lines changed

14 files changed

+240
-62
lines changed

CHANGELOG.md

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
See also: [compojure-api 1.1.x changelog](./CHANGELOG-1.1.x.md)
22

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

510
## 2.0.0-alpha33 (2024-04-30)
611
* Throw an error on malformed `:{body,query,headers}`, in particular if anything other than 2 elements was provided

examples/thingie/src/examples/thingie.clj

+2-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@
2626

2727
(def app
2828
(api
29-
{:swagger
29+
{:formatter :muuntaja
30+
:swagger
3031
{:ui "/"
3132
:spec "/swagger.json"
3233
:data {:info {:version "1.0.0"

src/compojure/api/api.clj

+17-1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,21 @@
5353
api
5454
[& body]
5555
(let [[options handlers] (common/extract-parameters body false)
56+
_ (assert (not (contains? options :format))
57+
(str "ERROR: Option [:format] is not used with 2.* version.\n"
58+
"Compojure-api uses now Muuntaja insted of ring-middleware-format,\n"
59+
"the new formatting options for it should be under [:formats]. See\n"
60+
"[[api-middleware]] documentation for more details.\n"))
61+
_ (when (and (not (:formatter options))
62+
(not (contains? options :formats))
63+
(not (System/getProperty "compojure.api.middleware.global-default-formatter")))
64+
(throw (ex-info (str "ERROR: Please set `:formatter :muuntaja` in the options map of `api`.\n"
65+
"e.g., (api {:formatter :muuntaja} routes...)\n"
66+
"To prepare for backwards compatibility with compojure-api 1.x, the formatting library must be\n"
67+
"explicitly chosen if not configured by `:format` (ring-middleware-format) or \n"
68+
"`:formats` (muuntaja). Once 2.x is stable, the default will be `:formatter :ring-middleware-format`.\n"
69+
"To globally override the formatter, use -Dcompojure.api.middleware.global-default-formatter=:muuntaja")
70+
{})))
5671
options (rsc/deep-merge api-defaults options)
5772
handler (apply c/routes (concat [(swagger/swagger-routes (:swagger options))] handlers))
5873
partial-api-route (routes/map->Route
@@ -63,7 +78,8 @@
6378
lookup (routes/route-lookup-table routes)
6479
swagger-data (get-in options [:swagger :data])
6580
enable-api-middleware? (not (get-in options [:api :disable-api-middleware?]))
66-
api-middleware-options (mw/api-middleware-options (dissoc options :api :swagger))
81+
api-middleware-options (dissoc (mw/api-middleware-options (assoc (dissoc options :api :swagger) ::via-api true))
82+
::mw/api-middleware-defaults)
6783
api-handler (-> handler
6884
(cond-> swagger-data (rsm/wrap-swagger-data swagger-data))
6985
(cond-> enable-api-middleware? (mw/api-middleware

src/compojure/api/middleware.clj

+44-2
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,8 @@
196196
;;
197197

198198
(def api-middleware-defaults
199-
{:formats ::default
199+
{::api-middleware-defaults true
200+
:formats ::default
200201
:exceptions {:handlers {:ring.util.http-response/response ex/http-response-handler
201202
::ex/request-validation ex/request-validation-handler
202203
::ex/request-parsing ex/request-parsing-handler
@@ -234,6 +235,15 @@
234235
235236
### Options
236237
238+
- **:formatter** either :ring-middleware-format or :muuntaja.
239+
During 2.x pre-releases, this will be a required key, unless
240+
:formats is provided, which is equivalent to setting to :muuntaja.
241+
Stable 2.x releases will default to :ring-middleware-format if
242+
not provided or :format is set, unless :formats is provided,
243+
which is equivalent to setting to :muuntaja.
244+
Stable 2.x will print a deprecation warning if implicitly
245+
or explicitly set to :ring-middleware-format.
246+
237247
- **:exceptions** for *compojure.api.middleware/wrap-exceptions* (nil to unmount it)
238248
- **:handlers** Map of error handlers for different exception types, type refers to `:type` key in ExceptionInfo data.
239249
@@ -256,9 +266,41 @@
256266
you might want to take look at using wrap-components
257267
middleware manually.). Defaults to nil (middleware not mounted)."
258268
([handler]
269+
(throw (ex-info (str "ERROR: Please set `:formatter :muuntaja` in the options map of `api-middleware.\n"
270+
"e.g., (api-middleware <handler> {:formatter :muuntaja})\n"
271+
"To prepare for backwards compatibility with compojure-api 1.x, the formatting library must be \n"
272+
"explicitly chosen if not configured by `:format` (ring-middleware-format) or\n"
273+
"`:formats` (muuntaja). Once 2.x is stable, the default will be `:formatter :ring-middleware-format`.")
274+
{}))
259275
(api-middleware handler api-middleware-defaults))
260276
([handler options]
261-
(let [options (api-middleware-options options)
277+
(when (and (::api-middleware-defaults options)
278+
(not (:formatter options))
279+
(not (System/getProperty "compojure.api.middleware.global-default-formatter")))
280+
(throw (ex-info (str "ERROR: Please set `:formatter :muuntaja` in the options map of `api-middleware.\n"
281+
"e.g., (api-middleware <handler> {:formatter :muuntaja})\n"
282+
"To prepare for backwards compatibility with compojure-api 1.x, the formatting library must be\n"
283+
"explicitly chosen if not configured by `:format` (ring-middleware-format) or\n"
284+
":formats (muuntaja). Once 2.x is stable, the default will be `:formatter :ring-middleware-format`.\n"
285+
"To globally override the default formatter, use -Dcompojure.api.middleware.global-default-formatter=:muuntaja")
286+
{})))
287+
(let [formatter (or (:formatter options)
288+
(when (or (contains? options :formats)
289+
(= (System/getProperty "compojure.api.middleware.global-default-formatter")
290+
":muuntaja"))
291+
:muuntaja)
292+
(throw (ex-info (str "ERROR: Please set `:formatter :muuntaja` in the options map of `api-middleware.\n"
293+
"e.g., (api-middleware <handler> {:formatter :muuntaja})\n"
294+
"To prepare for backwards compatibility with compojure-api 1.x, the formatting library must be\n"
295+
"explicitly chosen if not configured by `:format` (ring-middleware-format) or\n"
296+
":formats (muuntaja). Once 2.x is stable, the default will be `:formatter :ring-middleware-format`.\n"
297+
"To globally override the default formatter, use -Dcompojure.api.middleware.global-default-formatter=:muuntaja")
298+
{}))
299+
;; TODO 2.x stable
300+
:ring-middleware-format)
301+
_ (assert (= :muuntaja formatter)
302+
(str "Invalid :formatter: " (pr-str formatter) ". Must be :muuntaja."))
303+
options (api-middleware-options options)
262304
{:keys [exceptions components formats middleware ring-swagger coercion]} options
263305
muuntaja (create-muuntaja formats)]
264306

test/compojure/api/coercion/schema_coercion_test.clj

+2-1
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,8 @@
150150

151151
(deftest apis-test
152152
(let [app (api
153-
{:swagger {:spec "/swagger.json"}
153+
{:formatter :muuntaja
154+
:swagger {:spec "/swagger.json"}
154155
:coercion :schema}
155156

156157
(POST "/body" []

test/compojure/api/coercion_test.clj

+31-16
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,11 @@
3131
:default {:schema {:value s/Int}}}
3232
(ok {:value (or value "123")}))]
3333
(testing "200"
34-
(is-has-body {:value "123"} (get* (api r-200) "/"))
35-
(is-fails-with 500 (get* (api r-200) "/" {:value 123})))
34+
(is-has-body {:value "123"} (get* (api {:formatter :muuntaja} r-200) "/"))
35+
(is-fails-with 500 (get* (api {:formatter :muuntaja} r-200) "/" {:value 123})))
3636

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

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

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

5656
(testing "custom coercion"
5757

@@ -62,20 +62,23 @@
6262

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

6869
(testing "response-coercion can be disabled"
6970
(testing "separately"
7071
(let [app (api
71-
{:coercion (cs/create-coercion (dissoc cs/default-options :response))}
72+
{:formatter :muuntaja
73+
:coercion (cs/create-coercion (dissoc cs/default-options :response))}
7274
ping-route)]
7375
(let [[status body] (get* app "/ping")]
7476
(is (= 200 status))
7577
(is (= {:pong 123} body)))))
7678
(testing "all coercion"
7779
(let [app (api
78-
{:coercion nil}
80+
{:formatter :muuntaja
81+
:coercion nil}
7982
ping-route)]
8083
(let [[status body] (get* app "/ping")]
8184
(is (= 200 status))
@@ -84,12 +87,16 @@
8487
(testing "coercion for async handlers"
8588
(binding [*async?* true]
8689
(testing "successful"
87-
(let [app (api (GET "/async" []
90+
(let [app (api
91+
{:formatter :muuntaja}
92+
(GET "/async" []
8893
:return s/Str
8994
(a/go (ok "abc"))))]
9095
(is-has-body "abc" (get* app "/async"))))
9196
(testing "failing"
92-
(let [app (api (GET "/async" []
97+
(let [app (api
98+
{:formatter :muuntaja}
99+
(GET "/async" []
93100
:return s/Int
94101
(a/go (ok "foo"))))]
95102
(is-fails-with 500 (get* app "/async"))))))))
@@ -101,6 +108,7 @@
101108

102109
(testing "by default, applies body coercion (to set)"
103110
(let [app (api
111+
{:formatter :muuntaja}
104112
beer-route)]
105113
(let [[status body] (post* app "/beer" (json-string {:beers ["ipa" "apa" "ipa"]}))]
106114
(is (= 200 status))
@@ -109,13 +117,15 @@
109117
(testing "body-coercion can be disabled"
110118
(let [no-body-coercion (cs/create-coercion (dissoc cs/default-options :body))
111119
app (api
112-
{:coercion no-body-coercion}
120+
{:formatter :muuntaja
121+
:coercion no-body-coercion}
113122
beer-route)]
114123
(let [[status body] (post* app "/beer" (json-string {:beers ["ipa" "apa" "ipa"]}))]
115124
(is (= 200 status))
116125
(is (= {:beers ["ipa" "apa" "ipa"]} body))))
117126
(let [app (api
118-
{:coercion nil}
127+
{:formatter :muuntaja
128+
:coercion nil}
119129
beer-route)]
120130
(let [[status body] (post* app "/beer" (json-string {:beers ["ipa" "apa" "ipa"]}))]
121131
(is (= 200 status))
@@ -124,7 +134,8 @@
124134
(testing "body-coercion can be changed"
125135
(let [nop-body-coercion (cs/create-coercion (assoc cs/default-options :body {:default (constantly nil)}))
126136
app (api
127-
{:coercion nop-body-coercion}
137+
{:formatter :muuntaja
138+
:coercion nop-body-coercion}
128139
beer-route)]
129140
(is-fails-with 400 (post* app "/beer" (json-string {:beers ["ipa" "apa" "ipa"]})))))))
130141

@@ -135,6 +146,7 @@
135146

136147
(testing "by default, applies query coercion (string->int)"
137148
(let [app (api
149+
{:formatter :muuntaja}
138150
query-route)]
139151
(let [[status body] (get* app "/query" {:i 10})]
140152
(is (= 200 status))
@@ -143,7 +155,8 @@
143155
(testing "query-coercion can be disabled"
144156
(let [no-query-coercion (cs/create-coercion (dissoc cs/default-options :string))
145157
app (api
146-
{:coercion no-query-coercion}
158+
{:formatter :muuntaja
159+
:coercion no-query-coercion}
147160
query-route)]
148161
(let [[status body] (get* app "/query" {:i 10})]
149162
(is (= 200 status))
@@ -152,12 +165,14 @@
152165
(testing "query-coercion can be changed"
153166
(let [nop-query-coercion (cs/create-coercion (assoc cs/default-options :string {:default (constantly nil)}))
154167
app (api
155-
{:coercion nop-query-coercion}
168+
{:formatter :muuntaja
169+
:coercion nop-query-coercion}
156170
query-route)]
157171
(is-fails-with 400 (get* app "/query" {:i 10}))))))
158172

159173
(testing "route-specific coercion"
160174
(let [app (api
175+
{:formatter :muuntaja}
161176
(GET "/default" []
162177
:query-params [i :- s/Int]
163178
(ok {:i i}))

0 commit comments

Comments
 (0)