Skip to content

Commit 426049c

Browse files
committed
allow json coercion for exception cases based on :coerce setting, can
be either :always, :exceptional or :unexceptional. Fixes dakrone#118
1 parent 99cf57c commit 426049c

File tree

4 files changed

+64
-21
lines changed

4 files changed

+64
-21
lines changed

Readme.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,19 @@ The client transparently accepts and decompresses the `gzip` and
217217
;; stream has been read
218218
```
219219

220+
JSON coercion defaults to only an "unexceptional" statuses, meaning
221+
status codes in the #{200 201 202 203 204 205 206 207 300 301 302 303
222+
307} range. If you would like to change this, you can send the
223+
`:coerce` option, which can be set to:
224+
225+
```clojure
226+
:always ;; always json decode the body
227+
:unexceptional ;; only json decode when not an HTTP error response
228+
:exceptional ;; only json decode when it IS an HTTP error response
229+
```
230+
231+
The `:coerce` setting defaults to `:unexceptional`.
232+
220233
#### Body decompression
221234
By default, clj-http will add the `{"Accept-Encoding" "gzip, deflate"}`
222235
header to requests, and automatically decompress the resulting gzip or

changelog.org

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,9 @@
247247
* Work log
248248
Log of merges/issues/work that's gone in so I know what to put in
249249
the changelog for the next release
250+
** 2013-03-06
251+
- allow json coercion for exception cases based on :coerce setting,
252+
can be either :always, :exceptional or :unexceptional
250253
** 2013-03-01
251254
- Update clojure to 1.5
252255
- Move SingleClientConnManager shutdown into finally block

src/clj_http/client.clj

Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -203,29 +203,41 @@
203203
(decompress-body resp-c)))))
204204

205205
;; Multimethods for coercing body type to the :as key
206-
(defmulti coerce-response-body (fn [as _] as))
206+
(defmulti coerce-response-body (fn [req _] (:as req)))
207207

208208
(defmethod coerce-response-body :byte-array [_ resp] resp)
209209

210210
(defmethod coerce-response-body :stream [_ resp] resp)
211211

212-
(defmethod coerce-response-body :json [_ {:keys [body status] :as resp}]
213-
(if (and json-enabled? (unexceptional-status? status))
214-
(assoc resp :body (json-decode (String. #^"[B" body "UTF-8") true))
215-
(assoc resp :body (String. #^"[B" body "UTF-8"))))
212+
(defn coerce-json-body
213+
[{:keys [coerce]} {:keys [body status] :as resp} keyword? & [charset]]
214+
(let [charset (or charset "UTF-8")]
215+
(if json-enabled?
216+
(cond
217+
(= coerce :always)
218+
(assoc resp :body (json-decode (String. #^"[B" body charset) keyword?))
219+
220+
(and (unexceptional-status? status)
221+
(or (nil? coerce) (= coerce :unexceptional)))
222+
(assoc resp :body (json-decode (String. #^"[B" body charset) keyword?))
223+
224+
(and (not (unexceptional-status? status)) (= coerce :exceptional))
225+
(assoc resp :body (json-decode (String. #^"[B" body charset) keyword?))
216226

217-
(defmethod coerce-response-body
218-
:json-string-keys
219-
[_ {:keys [body status] :as resp}]
220-
(if (and json-enabled? (unexceptional-status? status))
221-
(assoc resp :body (json-decode (String. #^"[B" body "UTF-8")))
222-
(assoc resp :body (String. #^"[B" body "UTF-8"))))
227+
:else (assoc resp :body (String. #^"[B" body charset)))
228+
(assoc resp :body (String. #^"[B" body charset)))))
229+
230+
(defmethod coerce-response-body :json [req resp]
231+
(coerce-json-body req resp true))
232+
233+
(defmethod coerce-response-body :json-string-keys [_ resp]
234+
(coerce-json-body resp false))
223235

224236
(defmethod coerce-response-body :clojure [_ {:keys [status body] :as resp}]
225237
(binding [*read-eval* false]
226238
(assoc resp :body (read-string (String. #^"[B" body "UTF-8")))))
227239

228-
(defmethod coerce-response-body :auto [_ {:keys [status body] :as resp}]
240+
(defmethod coerce-response-body :auto [_ {:keys [body coerce status] :as resp}]
229241
(assoc resp
230242
:body
231243
(let [typestring (get-in resp [:headers "content-type"])]
@@ -247,13 +259,14 @@
247259
json-enabled?)
248260
(if-let [charset (second (re-find #"charset=(.*)"
249261
(str typestring)))]
250-
(json-decode (String. #^"[B" body ^String charset) true)
251-
(json-decode (String. #^"[B" body "UTF-8") true))
262+
(coerce-json-body resp true charset)
263+
(coerce-json-body resp true "UTF-8"))
252264

253265
:else
254266
(String. #^"[B" body "UTF-8")))))
255267

256-
(defmethod coerce-response-body :default [as {:keys [status body] :as resp}]
268+
(defmethod coerce-response-body :default
269+
[{:keys [as]} {:keys [status body] :as resp}]
257270
(cond
258271
(string? as) (assoc resp :body (String. #^"[B" body ^String as))
259272
:else (assoc resp :body (String. #^"[B" body "UTF-8"))))
@@ -264,10 +277,10 @@
264277
`coerce-response-body` multimethod may be extended to add
265278
additional coercions."
266279
[client]
267-
(fn [{:keys [as] :as req}]
280+
(fn [req]
268281
(let [{:keys [body] :as resp} (client req)]
269282
(if body
270-
(coerce-response-body as resp)
283+
(coerce-response-body req resp)
271284
resp))))
272285

273286
(defn maybe-wrap-entity

test/clj_http/test/core.clj

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -295,13 +295,27 @@
295295
(deftest ^{:integration true} t-json-output-coercion
296296
(run-server)
297297
(let [resp (client/get (localhost "/json") {:as :json})
298+
resp-str (client/get (localhost "/json")
299+
{:as :json :coerce :exceptional})
298300
bad-resp (client/get (localhost "/json-bad")
299-
{:throw-exceptions false :as :json})]
300-
(is (= 200 (:status resp)))
301+
{:throw-exceptions false :as :json})
302+
bad-resp-json (client/get (localhost "/json-bad")
303+
{:throw-exceptions false :as :json
304+
:coerce :always})
305+
bad-resp-json2 (client/get (localhost "/json-bad")
306+
{:throw-exceptions false :as :json
307+
:coerce :unexceptional})]
308+
(is (= 200 (:status resp) (:status resp-str)))
301309
(is (= {:foo "bar"} (:body resp)))
302-
(is (= 400 (:status bad-resp)))
310+
(is (= "{\"foo\":\"bar\"}" (:body resp-str)))
311+
(is (= 400
312+
(:status bad-resp)
313+
(:status bad-resp-json)
314+
(:status bad-resp-json2)))
303315
(is (= "{\"foo\":\"bar\"}" (:body bad-resp))
304-
"don't coerce on bad response status")))
316+
"don't coerce on bad response status by default")
317+
(is (= {:foo "bar"} (:body bad-resp-json)))
318+
(is (= "{\"foo\":\"bar\"}" (:body bad-resp-json2)))))
305319

306320
(deftest ^{:integration true} t-ipv6
307321
(run-server)

0 commit comments

Comments
 (0)