Skip to content

Commit 422d5e7

Browse files
committed
feat(api): new api layer WIP
1 parent 5c3712f commit 422d5e7

File tree

3 files changed

+144
-0
lines changed

3 files changed

+144
-0
lines changed

src/main/parts/frontend/api/core.cljs

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

src/main/parts/frontend/app.cljs

+5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
(ns parts.frontend.app
22
(:require
33
["htmx.org" :default htmx]
4+
[parts.frontend.state :as state]
5+
[parts.frontend.api.core :as api]
46
[parts.frontend.components.system :refer [system]]
57
[uix.core :refer [defui $]]
68
[uix.dom]))
@@ -30,6 +32,9 @@
3032
(defn ^:export init []
3133
(.on htmx "htmx:load"
3234
(fn [_]
35+
(state/init!)
36+
(api/init!)
37+
3338
(render-app)
3439
(let [version (.-version htmx)]
3540
(js/console.log "HTMX loaded! Version:" version)))))

src/main/parts/frontend/state.cljs

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
(ns parts.frontend.state)
2+
3+
;; TODO: State management!
4+
5+
(defn set-entities! [data]
6+
(println "set-entities!" data))
7+
8+
(defn add-entity! [data]
9+
(println "add-entity!" data))
10+
11+
(defn update-entity! [data]
12+
(println "update-entity!" data))
13+
14+
(defn remove-entity! [data]
15+
(println "delete-entity!" data))
16+
17+
(defn set-error! [data]
18+
(println "set-error!" data))
19+
20+
(defn get-auth-token []
21+
(str "placeholder-token-change-me"))
22+
23+
(defn init! []
24+
(println "State manager initialised"))

0 commit comments

Comments
 (0)