|
1 | 1 | (ns parts.frontend.api.core
|
2 |
| - (:require [cljs.core.async :refer [chan put! <! go go-loop timeout]] |
3 |
| - [cljs-http.client :as http] |
4 |
| - [cognitect.transit :as t] |
5 |
| - [parts.frontend.utils.api :as utils] |
6 |
| - [parts.frontend.state :as state])) |
7 |
| - |
8 |
| -;; Core channels: request, response, events |
9 |
| -(def request-channel (chan 10)) |
10 |
| -(def response-channel (chan 10)) |
11 |
| -(def event-channel (chan 10)) |
12 |
| - |
13 |
| -(def request-types |
14 |
| - {:fetch-data {:method :get} |
15 |
| - :create-entity {:method :post} |
16 |
| - :update-entity {:method :put} |
17 |
| - :partially-update-entity {:method :patch} |
18 |
| - :delete-entity {:method :delete} |
19 |
| - ;; Example: |
20 |
| - ;; :search {:method :get, :throttle 300} |
21 |
| - }) |
22 |
| - |
23 |
| -(defn- build-request [req-type endpoint params] |
24 |
| - (let [base-config (get request-types req-type) |
25 |
| - method (:method base-config) |
26 |
| - headers {"Authorization" (utils/get-auth-header) |
27 |
| - "Accept" "application/transit+json"}] |
28 |
| - {:method method |
29 |
| - :url (str "/api" endpoint) |
30 |
| - :headers headers |
31 |
| - :params params |
32 |
| - :type req-type})) |
33 |
| - |
34 |
| -(defn- start-request-manager [] |
35 |
| - (go-loop [] |
36 |
| - (let [request (<! request-channel) |
37 |
| - {:keys [method url headers params type]} request] |
38 |
| - (println "[request]" request) |
39 |
| - (when-let [throttle-ms (get-in request-types [type :throttle])] |
40 |
| - (<! (timeout throttle-ms))) |
41 |
| - |
42 |
| - (go |
43 |
| - (try |
44 |
| - (let [response (<! (case method |
45 |
| - :get (http/get url {:headers headers :query-params params :accept :transit+json}) |
46 |
| - :post (http/post url {:headers headers :transit-params params :accept :transit+json}) |
47 |
| - :put (http/put url {:headers headers :transit-params params :accept :transit+json}) |
48 |
| - :patch (http/patch url {:headers headers :transit-params params :accept :transit+json}) |
49 |
| - :delete (http/delete url {:headers headers :accept :transit+json})))] |
50 |
| - (if (< (:status response) 400) |
51 |
| - (put! response-channel {:type type |
52 |
| - :request request |
53 |
| - :response response |
54 |
| - :status :success}) |
55 |
| - (put! response-channel {:type type |
56 |
| - :request request |
57 |
| - :error {:message (str "HTTP Error: " (:status response)) |
58 |
| - :response response} |
59 |
| - :status :error}))) |
60 |
| - (catch js/Error e |
61 |
| - (put! response-channel {:type type |
62 |
| - :request request |
63 |
| - :error e |
64 |
| - :status :error})))) |
65 |
| - (recur)))) |
66 |
| - |
67 |
| -(defn- start-response-handler [] |
68 |
| - (go-loop [] |
69 |
| - (let [{:keys [type request response error status]} (<! response-channel)] |
70 |
| - (cond |
71 |
| - (= status :success) |
72 |
| - (let [data (-> response :body)] |
73 |
| - (case type |
74 |
| - :fetch-data (state/set-entities! data) |
75 |
| - :create-entity (state/add-entity! data) |
76 |
| - :update-entity (state/update-entity! data) |
77 |
| - :delete-entity (state/remove-entity! (:id (:params request)))) |
78 |
| - |
79 |
| - (put! event-channel {:event :api-success |
80 |
| - :type type |
81 |
| - :data data})) |
82 |
| - (= status :error) |
83 |
| - (let [error-data {:message (or (-> error .-message) "Unknown error") |
84 |
| - :type type |
85 |
| - :request request}] |
86 |
| - (state/set-error! error-data) |
87 |
| - (put! event-channel {:event :api-error |
88 |
| - :error error-data}))) |
89 |
| - (recur)))) |
90 |
| - |
91 |
| -(defn fetch-data [endpoint & [params]] |
92 |
| - (put! request-channel (build-request :fetch-data endpoint params)) |
93 |
| - (let [result-channel (chan)] |
94 |
| - (go |
95 |
| - (loop [] |
96 |
| - (let [event (<! event-channel)] |
97 |
| - (println "fetch-data" event) |
98 |
| - (if (and (= (:event event) :api-success) |
99 |
| - (= (:type event) :fetch-data)) |
100 |
| - (put! result-channel (:data event)) |
101 |
| - (recur))))) |
102 |
| - result-channel)) |
103 |
| - |
104 |
| -(defn create-entity [endpoint entity] |
105 |
| - (put! request-channel (build-request :create-entity endpoint entity))) |
106 |
| - |
107 |
| -(defn update-entity [endpoint entity] |
108 |
| - (put! request-channel (build-request :update-entity endpoint entity))) |
109 |
| - |
110 |
| -(defn delete-entity [endpoint id] |
111 |
| - (put! request-channel (build-request :delete-entity endpoint {:id id}))) |
112 |
| - |
113 |
| -(defn init! [] |
114 |
| - (start-request-manager) |
115 |
| - (start-response-handler) |
116 |
| - (println "API layer initialised")) |
| 2 | + (:require [cljs.core.async :refer [<! go]] |
| 3 | + [cljs-http.client :as http])) |
| 4 | + |
| 5 | +;; Helpers |
| 6 | + |
| 7 | +(defn- get-auth-token [] |
| 8 | + (js/lcalStorage.getItem "auth-token")) |
| 9 | + |
| 10 | +(defn- add-auth-header [req] |
| 11 | + (if-let [token (js/localStorage.getItem "auth-token")] |
| 12 | + (assoc-in req [:headers "Authorization"] (str "Bearer " token)) |
| 13 | + req)) |
| 14 | + |
| 15 | +(defn GET [endpoint params] |
| 16 | + (go (<! (http/get (str "/api" endpoint) |
| 17 | + (-> {:query-params params |
| 18 | + :accept :transit+json} |
| 19 | + add-auth-header))))) |
| 20 | + |
| 21 | +(defn POST [endpoint data] |
| 22 | + (go (<! (http/post (str "/api" endpoint) |
| 23 | + (-> {:transit-params data |
| 24 | + :accept :transit+json} |
| 25 | + add-auth-header))))) |
| 26 | + |
| 27 | +(defn PUT [endpoint data] |
| 28 | + (go (<! (http/put (str "/api" endpoint) |
| 29 | + (-> {:transit-params data |
| 30 | + :accept :transit+json} |
| 31 | + add-auth-header))))) |
| 32 | + |
| 33 | +(defn PATCH [endpoint data] |
| 34 | + (go (<! (http/patch (str "/api" endpoint) |
| 35 | + (-> {:transit-params data |
| 36 | + :accept :transit+json} |
| 37 | + add-auth-header))))) |
| 38 | + |
| 39 | +(defn DELETE [endpoint] |
| 40 | + (go (<! (http/delete (str "/api" endpoint) |
| 41 | + (-> {:accept :transit+json} |
| 42 | + add-auth-header))))) |
| 43 | + |
| 44 | +;; Auth |
| 45 | + |
| 46 | +(defn login [credentials] |
| 47 | + (go |
| 48 | + (let [response (<! (POST "/auth/login" credentials))] |
| 49 | + (when (= 200 (:status response)) |
| 50 | + (js/localStorage.setItem "auth-token" (get-in response [:body :token]))) |
| 51 | + response))) |
| 52 | + |
| 53 | +(defn logout [] |
| 54 | + (js/localStorage.removeItem "auth-token")) |
| 55 | + |
| 56 | +;; Account |
| 57 | + |
| 58 | +(defn get-current-user [] |
| 59 | + (GET "/account" {})) |
0 commit comments