Skip to content

Commit 03df7de

Browse files
Start using a defhandler macro for defining handlers (#69)
* Start using a defhandler macro for defining handlers * Polylith commands * Fix tests * Fix linting
1 parent f744a61 commit 03df7de

File tree

6 files changed

+87
-24
lines changed

6 files changed

+87
-24
lines changed

.claude/settings.local.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"permissions": {
3+
"allow": [
4+
"Bash(clj:*)"
5+
],
6+
"deny": []
7+
}
8+
}

CLAUDE.md

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ bb psql-test # Connect to test PostgreSQL database
4545
**REPL Development:**
4646
```bash
4747
clj -M:dev:repl # Development REPL
48-
clj -M:test:repl # Test REPL
4948
```
5049

5150
**Build Commands:**
@@ -56,8 +55,18 @@ clj -T:build uberjar :project agent # Build agent uberjar
5655

5756
**Testing:**
5857
```bash
59-
# Test runner is configured in tests.edn using Kaocha
60-
clj -M:poly test
58+
clj -M:poly test # Run tests for all projects
59+
```
60+
61+
**Polylith Commands:**
62+
```bash
63+
clj -M:poly info # Show workspace info and project structure
64+
clj -M:poly deps # Show dependencies between components
65+
clj -M:poly check # Check for circular dependencies and issues
66+
clj -M:poly diff # Show what has changed since last tag
67+
clj -M:poly create component name:my-component # Create new component
68+
clj -M:poly create base name:my-base # Create new base
69+
clj -M:poly create project name:my-project # Create new project
6170
```
6271

6372
## Development Workflow
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
(ns com.vennbilling.http.core
2+
(:require [ring.util.http-response :as http]))
3+
4+
(defn respond-with
5+
"Converts handler result tuples like [:ok data] into proper HTTP responses"
6+
[result]
7+
(let [[status body] result]
8+
(case status
9+
:ok (http/ok body)
10+
:created (http/created "" body)
11+
:no-content (http/no-content)
12+
:bad-request (http/bad-request body)
13+
:not-found (http/not-found body)
14+
(http/bad-request body))))
15+
16+
(defmacro defhandler
17+
"Defines a handler function that automatically applies respond-with to the result.
18+
19+
Usage:
20+
(defhandler my-handler [request]
21+
[:ok {:message \"Hello\"}])
22+
23+
This is equivalent to:
24+
(defn my-handler [request]
25+
(respond-with [:ok {:message \"Hello\"}]))"
26+
[name args & body]
27+
`(defn ~name ~args
28+
(respond-with (do ~@body))))

components/http/src/com/vennbilling/http/interface.clj

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
(ns com.vennbilling.http.interface
2-
(:require [com.vennbilling.http.ring :as ring]
2+
(:require [com.vennbilling.http.core :as core]
3+
[com.vennbilling.http.ring :as ring]
34
[com.vennbilling.http.routes :as routes]
45
[com.vennbilling.http.undertow :as undertow]))
56

@@ -10,6 +11,13 @@
1011
(def server-routes
1112
[routes/customers])
1213

14+
(defmacro defhandler
15+
"Defines a handler function that automatically applies respond-with to the result.
16+
See com.vennbilling.http.core/defhandler for implementation details."
17+
{:clj-kondo/lint {:lint-as {core/defhandler clojure.core/fn}}}
18+
[name args & body]
19+
`(core/defhandler ~name ~args ~@body))
20+
1321
(defn serve
1422
"Starts up an HTTP server with a io.undertow config and ring handler. Returns an undertow server"
1523
[config handler]

components/http/src/com/vennbilling/http/routes.clj

Lines changed: 8 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,50 +2,39 @@
22
(:require [com.vennbilling.customer.interface :as customer]
33
[com.vennbilling.healthcheck.interface :as healthcheck]
44
[com.vennbilling.spec.interface :as spec]
5-
[ring.util.http-response :as http]
5+
[com.vennbilling.http.core :as core]
66
[ring.util.http-status :as http-status]))
77

8-
(defn- respond-with
9-
[result]
10-
(let [[status body] result]
11-
(case status
12-
:ok (http/ok body)
13-
:created (http/created "" body)
14-
:no-content (http/no-content)
15-
:bad-request (http/bad-request body)
16-
:not-found (http/not-found body)
17-
(http/bad-request body))))
18-
198
(def healthchecks
209
[["/health"
2110
{:get {:responses {http-status/ok {:body map?}
2211
http-status/internal-server-error {}}
23-
:handler (comp respond-with healthcheck/simple-handler)}}]])
12+
:handler (comp core/respond-with healthcheck/simple-handler)}}]])
2413

2514
(def spec
2615
[["/identify"
2716
{:post {:parameters {:body customer/Schema}
2817
:responses {http-status/created {:body customer/Schema}}
29-
:handler (comp respond-with spec/identify-handler)}}]
18+
:handler (comp core/respond-with spec/identify-handler)}}]
3019

3120
["/charge"
3221
{:post {:parameters {:body spec/Schema}
33-
:handler (comp respond-with spec/charge-handler)}}]
22+
:handler (comp core/respond-with spec/charge-handler)}}]
3423

3524
["/usage"
3625
{:post {:parameters {:body spec/Schema}
37-
:handler (comp respond-with spec/usage-handler)}}]
26+
:handler (comp core/respond-with spec/usage-handler)}}]
3827

3928
["/reverse"
4029
{:post {:parameters {:body spec/Schema}
41-
:handler (comp respond-with spec/reverse-handler)}}]])
30+
:handler (comp core/respond-with spec/reverse-handler)}}]])
4231

4332
(def customers
4433
["/customers"
4534
[""
4635
{:get {:responses {http-status/ok {:body [:vector customer/Schema]}}
47-
:handler (comp respond-with customer/list-handler)}}]
36+
:handler (comp core/respond-with customer/list-handler)}}]
4837
["/:id"
4938
{:get {:responses {http-status/ok {:body customer/Schema}
5039
http-status/not-found {}}
51-
:handler (comp respond-with customer/show-handler)}}]])
40+
:handler (comp core/respond-with customer/show-handler)}}]])
Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,22 @@
1-
(ns com.vennbilling.http.interface-test)
1+
(ns com.vennbilling.http.interface-test
2+
(:require
3+
[clojure.test :refer [deftest testing is]]
4+
[com.vennbilling.http.interface :refer [defhandler]]))
5+
6+
(defhandler test-handler [_request]
7+
[:ok {:message "test"}])
8+
9+
(defhandler test-created-handler [_request]
10+
[:created {:id 123}])
11+
12+
(deftest defhandler-macro-test
13+
(testing "defhandler macro creates proper HTTP responses"
14+
(testing "ok response"
15+
(let [response (test-handler {})]
16+
(is (= 200 (:status response)))
17+
(is (= {:message "test"} (:body response)))))
18+
19+
(testing "created response"
20+
(let [response (test-created-handler {})]
21+
(is (= 201 (:status response)))
22+
(is (= {:id 123} (:body response)))))))

0 commit comments

Comments
 (0)