-
Notifications
You must be signed in to change notification settings - Fork 0
/
api_async.cljs
130 lines (111 loc) · 3.59 KB
/
api_async.cljs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
(ns dgknght.app-lib.api-async
(:refer-clojure :exclude [get])
(:require [cljs-http.client :as http]
[cljs.core.async :as a]
[dgknght.app-lib.api :as api]))
(defn- extract-error
[m]
(if (:success m)
m
(let [error (try
(api/extract-error m)
(catch js/Error _e
"Unable to parse the body as JSON"))]
(assoc m ::error error))))
(defn- extract-res-body
[{:keys [body] :as res}]
(or body res)) ; ensure we don't put nil on the channel
(defn- throw-on-non-success
[m]
(when-let [error (::error m)]
(throw (js/Error. error)))
m)
(defn- concatv
[& s]
(vec (apply concat s)))
(defn- singular?
[v]
(and v
(not (sequential? v))))
(defn- build-xf
[{:keys [transform handle-ex extract-body]}]
(apply comp
(cond-> [(map extract-error)]
handle-ex (conj (map throw-on-non-success))
(#{true :before} extract-body) (conj (map extract-res-body))
(sequential? transform) (concatv transform)
(singular? transform) (conj transform)
(= :after extract-body) (conj (map extract-res-body)))))
(defn request
[options]
{:pre [(map? options)]}
(let [opts (merge @api/defaults options)]
(assoc opts :channel (a/chan 1
(build-xf opts)
(:handle-ex opts)))))
(defn get
([path] (get path {}))
([path criteria] (get path criteria {}))
([path criteria options]
(http/get (api/append-query-string path criteria)
(request options))))
(defn post
([path resource] (post path resource {}))
([path resource options]
(http/post path (-> options
request
(assoc :json-params resource)))))
(defn put
([path resource] (put path resource {}))
([path resource options]
(http/put path (-> options
request
(assoc :json-params resource)))))
(defn patch
([path resource] (patch path resource {}))
([path resource options]
(http/patch path (-> options
request
(assoc :json-params resource)))))
(defn delete
([path] (delete path {}))
([path options] (delete path nil options))
([path resource options]
(http/delete path (-> options
request
(assoc :json-params resource)))))
(def path api/path)
(defn multipart-params
[req params]
(assoc req :multipart-params params))
(defn apply-fn
"Given a function that accepts a single argument, returns a transducing
function that applies the given function either to each value as a whole,
or each element of each values if the value is sequential.
This would be appropriate for use with option {:extract-body :before}"
[f]
(fn [xf]
(completing
(fn [ch v]
(xf ch
(if (sequential? v)
(map f v)
(f v)))))))
(defn apply-body-fn
"Given a function that accepts a single argument, returns a transducing
function that applies the given function either to the body of a
response map or to each element in the body of the response map if the
body is sequential.
This would be appropriate for option {:extract-body :after} or without
the :extract-body option."
[f]
(fn [xf]
(completing
(fn [ch res]
(xf ch
(update-in res
[:body]
(fn [b]
(if (sequential? b)
(map f b)
(f b)))))))))