This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-09-12
Channels
- # adventofcode (1)
- # announcements (1)
- # atom-editor (4)
- # aws (4)
- # babashka (7)
- # beginners (46)
- # biff (14)
- # calva (11)
- # cljdoc (2)
- # clojure (78)
- # clojure-art (1)
- # clojure-austin (1)
- # clojure-europe (50)
- # clojure-nl (2)
- # clojure-norway (22)
- # clojure-spec (2)
- # clojure-uk (2)
- # clojurescript (72)
- # conjure (6)
- # core-typed (6)
- # eastwood (4)
- # events (1)
- # figwheel-main (11)
- # fulcro (1)
- # guix (1)
- # helix (13)
- # jobs (2)
- # jobs-discuss (4)
- # kaocha (2)
- # malli (5)
- # off-topic (7)
- # pathom (22)
- # pedestal (9)
- # re-frame (29)
- # reagent (7)
- # releases (2)
- # remote-jobs (1)
- # rewrite-clj (12)
- # shadow-cljs (44)
- # sql (13)
- # squint (2)
- # xtdb (17)
Hey folks, what is the recommended folder structure for a medium application using Pedestal? I saw in the book Microservices with Clojure an approach that I felt a little bit strange of using everything as interceptors. Here is the official https://github.com/PacktPublishing/Microservices-with-Clojure/tree/master/Chapter10/helping-hands-alert.chapter-10/src/clj/helping_hands/alert from the book:
;; Tabular routes
(def routes #{["/alerts/email"
:post (conj common-interceptors `auth `core/validate
`core/send-email `gen-events)
:route-name :alert-email]
["/alerts/sms"
:post (conj common-interceptors `auth `core/validate
`core/send-sms `gen-events)
:route-name :alert-sms]})
Validation interceptor:
(def validate
{:name ::validate
:enter
(fn [context]
(if-let [params (-> context :request :form-params)]
;; validate and return a context with tx-data
;; or terminated interceptor chain
(prepare-valid-context context)
(chain/terminate
(assoc context
:response {:status 400
:body "Invalid parameters"}))))
:error
(fn [context ex-info]
(assoc context
:response {:status 500
:body (.getMessage ex-info)}))})
Business logic interceptor:
(def send-email
{:name ::send-email
:enter
(fn [context]
(let [tx-data (:tx-data context)
msg (into {} (filter (comp some? val)
{:from ""
:to (:to tx-data)
:cc (:cc tx-data)
:subject (:subject tx-data)
:body (:body tx-data)}))
result (postal/send-message
{:host ""
:port 465
:ssl true
:user ""
:pass "resetme"}
msg)]
;; send email
(assoc context :response
{:status 200
:body (jp/generate-string result)})))
:error
(fn [context ex-info]
(assoc context
:response {:status 500
:body (.getMessage ex-info)}))})
In OO languages usually I would organize my application in something like Hexagonal Architecture, MVC or any other well spread pattern.
Do you have any suggestion for organization?Project #polylith is gaining traction in the clojure community as an opinionated approach to structure a clj codebase.
Thank you Thomas, I will take a look!
That's a bit of an open-ended question. It's like anything else, use a structure that grows with you. I would probably look for distinct sub-domains and have a namespace for each (for example, for E-commerce it might be product-catalog, product-detail, shopping-card, check-out, and so forth). I would also look for cross-cutting concerns such as auth and have a namespace for that.
Thank you Howard! My initial idea was split by feature like you suggested. I prefer do it in a way where I put other files near to where they are used instead of just split by responsibilities. E.g: avoid having folders for controllers, services, adapters and so on.
My only advice is grow on demand.
Don't start your project creating tons of namespaces "that will be important", like *.interceptos
*.handlers.*entity
*.routes
...
Start on a single file, once you see that there is a collection of things that make sense to have it own namespace, create it. give it a good name, not like .utils
or .things-that-i-dont-like
In Pedestal, everything ultimately ends up as an Interceptor (even routes!), but for many cases, there are helpers; for example, http://pedestal.io/api/pedestal.interceptor/io.pedestal.interceptor.helpers.html#var-defhandler lets you define a Ring-style handler for the end of your interceptor chain.