🎯 empfohlene Sammlungen
Balanced sample collections from various categories for you to explore
Clojure Sprachbeispiele
Wesentliche Clojure Programmierbeispiele für funktionale Programmierung auf der JVM
💻 Clojure Hello World clojure
🟢 simple
⭐⭐
Basis Hello World Programm in Clojure und fundamentale Lisp-style funktionale Programmierkonzepte
⏱️ 20 min
🏷️ clojure, functional, lisp, jvm, syntax
Prerequisites:
Basic programming concepts, Understanding of functional programming
;; Clojure Hello World Examples
;; 1. Basic Hello World
(println "Hello, World!")
;; 2. Hello World with function definition
(defn hello-world []
(println "Hello, World!"))
(hello-world)
;; 3. Hello World with parameters
(defn greet [name]
(println (str "Hello, " name "!")))
(greet "Clojure")
(greet "World")
;; 4. Hello World with multiple arities
(defn multi-greet
([] (println "Hello, World!"))
([name] (println (str "Hello, " name "!")))
([greeting name] (println (str greeting ", " name "!"))))
(multi-greet)
(multi-greet "Clojure")
(multi-greet "Good morning" "Clojure")
;; 5. Hello World with anonymous function
(let [greet-fn (fn [name] (println (str "Hello, " name "!")))]
(greet-fn "Anonymous"))
;; 6. Hello World with higher-order function
(defn greet-twice [greet-fn name]
(greet-fn name)
(greet-fn name))
(greet-twice greet "Twice")
;; Basic data types and operations
;; Numbers
(def num1 42)
(def num2 3.14)
(def num3 2/3) ; Rational number
(println "Integer:" num1)
(println "Float:" num2)
(println "Rational:" num3)
(println "Addition:" (+ num1 num2))
(println "Multiplication:" (* num1 2))
;; Strings
(def text "Clojure Programming")
(println "String:" text)
(println "Length:" (count text))
(println "Uppercase:" (clojure.string/upper-case text))
(println "Substring:" (subs text 0 6))
;; Keywords (efficient identifiers)
(def status :active)
(def user {:name "Alice" :age 30 :status status})
(println "User:" user)
(println "User name:" (:name user))
(println "User age:" (:age user))
;; Vectors (ordered collections)
(def numbers [1 2 3 4 5])
(println "Vector:" numbers)
(println "First element:" (first numbers))
(println "Last element:" (last numbers))
(println "Rest:" (rest numbers))
(println "Conj:" (conj numbers 6))
;; Maps (key-value collections)
(def person {
:name "Bob"
:age 25
:city "New York"
:hobbies ["reading" "coding" "music"]
})
(println "Person:" person)
(println "Person name:" (:name person))
(println "Person hobbies:" (:hobbies person))
;; Sets (unique collections)
(def unique-numbers #{1 2 3 4 5})
(println "Set:" unique-numbers)
(println "Contains 3?" (contains? unique-numbers 3))
(println "Add element:" (conj unique-numbers 6))
;; Lists (linked lists)
(def list-data '(1 2 3 4 5))
(println "List:" list-data)
(println "First:" (first list-data))
(println "Rest:" (rest list-data))
;; Basic functions
;; Function with multiple return values (using vector)
(defn divide-and-remainder [dividend divisor]
(let [quotient (quot dividend divisor)
remainder (rem dividend divisor)]
[quotient remainder]))
(let [[q r] (divide-and-remainder 17 5)]
(println "17 ÷ 5 =" q "remainder" r))
;; Conditional logic
(defn describe-number [n]
(cond
(< n 0) "negative"
(= n 0) "zero"
(< n 10) "small positive"
:else "large positive"))
(println "-5 is" (describe-number -5))
(println "0 is" (describe-number 0))
(println "5 is" (describe-number 5))
(println "15 is" (describe-number 15))
;; Pattern matching with case
(defn describe-value [x]
(case x
1 "one"
2 "two"
3 "three"
"hello" "greeting"
:keyword "a keyword"
"unknown value"))
(println "Value of 1:" (describe-value 1))
(println "Value of 'hello':" (describe-value "hello"))
;; Recursion
(defn factorial [n]
(if (<= n 1)
1
(* n (factorial (dec n)))))
(println "5! =" (factorial 5))
;; Tail recursion optimization
(defn factorial-tail [n acc]
(if (<= n 1)
acc
(recur (dec n) (* n acc))))
(defn factorial [n]
(factorial-tail n 1))
(println "10! =" (factorial 10))
;; Loop/recur for iteration
(defn sum-to [n]
(loop [i 1 total 0]
(if (> i n)
total
(recur (inc i) (+ total i)))))
(println "Sum of 1 to 100:" (sum-to 100))
;; Higher-order functions
;; Map - transform each element
(def doubled (map #(* % 2) [1 2 3 4 5]))
(println "Doubled:" doubled)
;; Filter - select elements
(def evens (filter even? [1 2 3 4 5 6]))
(println "Even numbers:" evens)
;; Reduce - aggregate elements
(def sum (reduce + [1 2 3 4 5]))
(println "Sum:" sum)
;; Function composition
(defn add-and-double [x]
(-> x
(+ 5)
(* 2)))
(println "Add 5 and double 10:" (add-and-double 10))
;; Destructuring
(defn process-person [{:keys [name age city] :as person}]
(println (str name " is " age " years old and lives in " city))
(println "Full person data:" person))
(process-person {:name "Charlie" :age 35 :city "Boston"})
;; Vector destructuring
(defn process-coordinates [[x y z]]
(println (str "X: " x ", Y: " y ", Z: " z)))
(process-coordinates [10 20 30])
;; Lazy sequences
(def naturals (iterate inc 1))
(def first-10 (take 10 naturals))
(println "First 10 natural numbers:" first-10)
(def even-numbers (filter even? naturals))
(def first-5-evens (take 5 even-numbers))
(println "First 5 even numbers:" first-5-evens)
;; Interoperability with Java
(import 'java.util.Date)
(import 'java.text.SimpleDateFormat)
(defn format-date [date]
(let [formatter (SimpleDateFormat. "yyyy-MM-dd HH:mm:ss")]
(.format formatter date)))
(def now (Date.))
(println "Current time:" (format-date now))
;; Using Java collections
(def java-list (java.util.ArrayList.))
(.add java-list "Java element")
(.add java-list "Another element")
(println "Java list:" (vec java-list))
;; Namespaces and requires (in real usage)
;; (ns my-app.core
;; (:require [clojure.string :as str]
;; [clojure.set :as set]))
;; Exception handling
(defn safe-divide [a b]
(try
(/ a b)
(catch ArithmeticException e
(println "Division by zero error!")
nil)
(finally
(println "Division operation completed"))))
(println "10 ÷ 2 =" (safe-divide 10 2))
(println "10 ÷ 0 =" (safe-divide 10 0))
;; Atom for state management
(def counter (atom 0))
(defn increment-counter []
(swap! counter inc))
(defn get-counter []
@counter)
(println "Initial counter:" @counter)
(increment-counter)
(increment-counter)
(println "Final counter:" @counter)
;; Basic meta-programming
(defmacro debug [x]
(let [result# ~x]
(println (str '~x " = " result#))
result#))
(def a 10)
(def b 20)
(debug (+ a b))
💻 Clojure Funktionale Programmiermuster clojure
🟡 intermediate
⭐⭐⭐⭐
Fortgeschrittene funktionale Programmierungstechniken, unveränderliche Datenstrukturen und gängige Clojure Muster
⏱️ 30 min
🏷️ clojure, functional, patterns, immutable, protocols
Prerequisites:
Clojure basics, Functional programming concepts, Data structures
;; Clojure Functional Programming Patterns
;; 1. Pure Functions and Immutability
;; Pure function - no side effects
(defn calculate-discount [price discount-rate]
(* price (- 1 discount-rate)))
(println "Discounted price:" (calculate-discount 100 0.2))
;; Always return new data structures instead of modifying
(defn add-item-to-cart [cart item]
(conj cart item))
(def original-cart [:book :pen])
(def new-cart (add-item-to-cart original-cart :notebook))
(println "Original cart:" original-cart) ; Unchanged
(println "New cart:" new-cart) ; New cart with added item
;; 2. Function Composition and Transducers
;; Function composition
(defn transform-data [data]
(->> data
(map #(* % 2)) ; Double each number
(filter even?) ; Keep only even numbers
(take 5) ; Take first 5
(reduce +))) ; Sum them up
(def numbers (range 1 20))
(println "Transform result:" (transform-data numbers))
;; Transducers - composable algorithmic transformations
(def xf-map-double (map #(* % 2)))
(def xf-filter-evens (filter even?))
(def xf-take-five (take 5))
(def process-numbers
(comp xf-map-double xf-filter-evens xf-take-five))
(println "Transducer result:" (into [] process-numbers numbers))
;; 3. Lazy Sequences and Infinite Data
;; Infinite sequence of Fibonacci numbers
(def fib-seq
(map first (iterate (fn [[a b]] [b (+ a b)]) [0 1])))
(def first-10-fib (take 10 fib-seq))
(println "First 10 Fibonacci numbers:" first-10-fib)
;; Lazy prime numbers
(defn prime? [n]
(and (> n 1)
(not-any? #(zero? (rem n %)) (range 2 (Math/sqrt n)))))
(def primes (filter prime? (iterate inc 2)))
(def first-10-primes (take 10 primes))
(println "First 10 prime numbers:" first-10-primes)
;; 4. Higher-Order Functions and Closures
;; Function factory - creates functions with captured values
(defn make-adder [increment]
(fn [x] (+ x increment)))
(def add-5 (make-adder 5))
(def add-10 (make-adder 10))
(println "Add 5 to 10:" (add-5 10))
(println "Add 10 to 10:" (add-10 10))
;; Predicate factory
(defn make-predicate [operator value]
(fn [x] (operator x value)))
(def greater-than-5 (make-predicate > 5))
(def less-than-10 (make-predicate < 10))
(println "Numbers >5:" (filter greater-than-5 [1 3 6 8 2 10]))
(println "Numbers <10:" (filter less-than-10 [1 3 6 8 2 10]))
;; 5. Data Transformation Pipelines
;; Pipeline for processing user data
(defn process-user-data [raw-users]
(->> raw-users
;; Remove inactive users
(filter #(:active %))
;; Calculate age group
(map #(assoc % :age-group
(cond
(< (:age %) 18) "minor"
(< (:age %) 65) "adult"
:else "senior")))
;; Sort by age
(sort-by :age)
;; Extract only relevant fields
(map #(select-keys % [:name :age :age-group]))))
(def raw-users [
{:name "Alice" :age 25 :active true :email "[email protected]"}
{:name "Bob" :age 17 :active true :email "[email protected]"}
{:name "Charlie" :age 70 :active false :email "[email protected]"}
{:name "Diana" :age 30 :active true :email "[email protected]"}])
(println "Processed users:" (process-user-data raw-users))
;; 6. Recursive Patterns and Tree Processing
;; Generic tree processing
(defn process-tree [node f-leaf f-node]
(if (:children node)
(f-node (:value node)
(map #(process-tree % f-leaf f-node) (:children node)))
(f-leaf (:value node))))
(def sample-tree
{:value "root"
:children [
{:value "left" :children [
{:value "left-left"}
{:value "left-right"}
]}
{:value "right" :children [
{:value "right-left"}
]}
]})
(defn sum-leaves [x]
(if (number? x) x 0))
(defn sum-node [value child-sums]
(+ (sum-leaves value) (reduce + child-sums)))
(def numeric-tree
{:value 1
:children [
{:value 2 :children [{:value 3} {:value 4}]}
{:value 5 :children [{:value 6}]}
]})
(println "Tree sum:" (process-tree numeric-tree sum-leaves sum-node))
;; 7. Memoization and Caching
;; Memoized expensive function
(defn slow-fibonacci [n]
(if (< n 2)
n
(+ (slow-fibonacci (dec n)) (slow-fibonacci (- n 2)))))
(def memo-fibonacci (memoize slow-fibonacci))
(println "Memoized fib 40:" (memo-fibonacci 40)) ; Much faster
;; Cache with TTL (time-to-live)
(defn create-ttl-cache [ttl-ms]
(let [cache (atom {})]
(fn [key f]
(let [now (System/currentTimeMillis)
cached-value (get @cache key)]
(if (and cached-value (< (- now (:timestamp cached-value)) ttl-ms))
(:value cached-value)
(let [new-value (f)]
(swap! cache assoc key {:value new-value :timestamp now})
new-value))))))
(def expensive-cache (create-ttl-cache 5000)) ; 5 second TTL
(defn expensive-calculation [x]
(println "Performing expensive calculation for" x)
(* x x x))
(println "Cached result:" (expensive-cache 10 expensive-calculation))
(println "Cached result again:" (expensive-cache 10 expensive-calculation))
;; 8. State Management Patterns
;; Event sourcing pattern
(defn add-event [state event]
(case (:type event)
:add-item (update state :items conj (:item event))
:remove-item (update state :items disj (:item event))
:update-quantity (assoc-in state [:quantities (:item event)] (:quantity event))
state))
(def initial-state {:items #{} :quantities {}})
(def events [
{:type :add-item :item :book}
{:type :add-item :item :pen}
{:type :update-quantity :item :book :quantity 2}
{:type :remove-item :item :pen}
])
(def final-state (reduce add-event initial-state events))
(println "Final state:" final-state)
;; 9. Protocol and Multimethod Patterns
;; Multimethods for polymorphic behavior
(defmulti area :shape)
(defmethod area :circle [{:keys [radius]}]
(* Math/PI radius radius))
(defmethod area :rectangle [{:keys [width height]}]
(* width height))
(defmethod area :triangle [{:keys [base height]}]
(* 0.5 base height))
(def shapes [
{:shape :circle :radius 5}
{:shape :rectangle :width 4 :height 6}
{:shape :triangle :base 3 :height 8}
])
(println "Areas:" (map area shapes))
;; Protocols for interface-like behavior
(defprotocol Drawable
(draw [this]))
(defrecord Circle [radius]
Drawable
(draw [this]
(println (str "Drawing circle with radius " radius))))
(defrecord Rectangle [width height]
Drawable
(draw [this]
(println (str "Drawing rectangle " width "x" height))))
(def shapes-objects [(->Circle 10) (->Rectangle 5 8)])
(dorun (map draw shapes-objects))
;; 10. Error Handling and Validation
;; Result pattern with explicit success/failure
(defn safe-divide [a b]
(if (zero? b)
{:success false :error "Division by zero"}
{:success true :result (/ a b)}))
(defn chain-operations [initial operations]
(reduce (fn [acc op]
(if (:success acc)
(op (:result acc))
acc))
initial
operations))
(def calculation-pipeline [
#(safe-divide % 2) ; Divide by 2
#(safe-divide % 0) ; This will fail
#(safe-divide % 3)]) ; This won't be reached
(println "Calculation result:" (chain-operations 100 calculation-pipeline))
;; Validation with accumulation
(defn validate-user [user]
(let [errors (cond-> []
(empty? (:name user)) (conj "Name is required")
(not (:email user)) (conj "Email is required")
(and (:age user) (< (:age user) 0)) (conj "Age must be non-negative"))]
(if (empty? errors)
{:success true :user user}
{:success false :errors errors})))
(def test-users [
{:name "Alice" :email "[email protected]" :age 25}
{:name "" :email "[email protected]" :age -5}
{}])
(println "Validation results:" (map validate-user test-users))
💻 Clojure Webentwicklung und Makros clojure
🔴 complex
⭐⭐⭐⭐⭐
Webentwicklung mit Ring/Compojure und fortgeschrittene Makroprogrammierung für Metaprogrammierung
⏱️ 45 min
🏷️ clojure, web, macros, ring, compojure, api
Prerequisites:
Advanced Clojure, Web concepts, Database knowledge, Macro understanding
;; Clojure Web Development and Advanced Macros
;; 1. Ring and Compojure Web Framework Basics
;; Basic Ring handler
(defn hello-handler [request]
{:status 200
:headers {"Content-Type" "text/html"}
:body "<h1>Hello from Clojure!</h1>"})
;; Route-based handler with Compojure
(require '[compojure.core :refer [defroutes GET POST]])
(require '[ring.adapter.jetty :as jetty])
(defroutes app-routes
(GET "/" [] "Welcome to the homepage!")
(GET "/hello/:name" [name] (str "Hello, " name "!"))
(GET "/api/users" []
{:status 200
:headers {"Content-Type" "application/json"}
:body "[{"id":1,"name":"Alice"},{"id":2,"name":"Bob"}]"})
(POST "/api/users" [name email]
{:status 201
:headers {"Content-Type" "application/json"}
:body (str "{"id":3,"name":"" name "","email":"" email ""}")})
(GET "/files/:filename" [filename]
(java.io.File. "public/" filename)))
;; Middleware for logging
(defn wrap-logging [handler]
(fn [request]
(println (str "Processing " (:request-method request) " " (:uri request)))
(let [response (handler request)]
(println (str "Response status: " (:status response)))
response)))
;; Middleware for JSON responses
(defn wrap-json [handler]
(fn [request]
(let [response (handler request)]
(if (map? (:body response))
(assoc-in response [:headers "Content-Type"] "application/json")
response))))
;; Middleware stack
(def app
(-> app-routes
wrap-logging
wrap-json))
;; 2. Advanced Macro Programming
;; Macro for route definition with automatic documentation
(defmacro defpage [route description & body]
(do
(defn ~(symbol (str "page-" (hash route))) [request#]
~@body)
(alter-var-root #'*routes* conj {:path ~route :description ~description})
~(symbol (str "page-" (hash route)))))
(def *routes* (atom []))
(defpage "/about" "About page"
{:status 200
:headers {"Content-Type" "text/html"}
:body "<h1>About Us</h1><p>We are a Clojure web application!</p>"})
;; Debugging macro with expression information
(defmacro dbg [x]
(let [result# ~x]
(println (str "Debug: " '~x " = " result#))
result#))
;; Time execution macro
(defmacro time-execution [& body]
(let [start# (System/nanoTime)
result# (do ~@body)
end# (System/nanoTime)
duration# (/ (- end# start#) 1000000.0)]
(println (str "Execution time: " duration# " ms"))
result#))
;; Usage example:
;; (time-execution
;; (Thread/sleep 100)
;; (println "Done"))
;; Conditional compilation macro
(defmacro when-dev [& body]
(when (= "development" (or (System/getenv "ENV") "development"))
~@body))
(when-dev
(println "Development mode enabled"))
;; 3. Database Operations and Transactions
(require '[clojure.java.jdbc :as jdbc])
(def db-spec {:subprotocol "h2"
:subname "mem:example"
:user "sa"
:password ""})
;; Table creation
(defn create-users-table! []
(jdbc/db-do-commands db-spec
[(jdbc/create-table-ddl :users
[[:id :int "PRIMARY KEY"]
[:name "VARCHAR(50)"]
[:email "VARCHAR(100)"]
[:created_at :timestamp]])]))
;; CRUD operations
(defn create-user! [user-data]
(jdbc/insert! db-spec :users
(assoc user-data :created_at (java.sql.Timestamp. (System/currentTimeMillis)))))
(defn get-user [id]
(first (jdbc/query db-spec ["SELECT * FROM users WHERE id = ?" id])))
(defn update-user! [id user-data]
(jdbc/update! db-spec :users user-data ["id = ?" id]))
(defn delete-user! [id]
(jdbc/delete! db-spec :users ["id = ?" id]))
(defn list-users []
(jdbc/query db-spec ["SELECT * FROM users ORDER BY created_at DESC"]))
;; Transaction example
(defn transfer-users! [from-id to-id]
(jdbc/with-db-transaction [t-conn db-spec]
(let [from-user (first (jdbc/query t-conn ["SELECT * FROM users WHERE id = ?" from-id]))
to-user (first (jdbc/query t-conn ["SELECT * FROM users WHERE id = ?" to-id]))]
(when (and from-user to-user)
;; Update both users in a single transaction
(jdbc/update! t-conn :users
{:name (str (:name from-user) "_transferred")}
["id = ?" from-id])
(jdbc/update! t-conn :users
{:name (str (:name to-user) "_received")}
["id = ?" to-id])
true))))
;; 4. Authentication and Authorization
;; Password hashing
(require '[buddy.hashers :as hashers])
(defn hash-password [password]
(hashers/derive password {:algorithm :bcrypt}))
(defn verify-password [password hashed-password]
(hashers/verify password hashed-password))
;; JWT token generation (requires buddy-sign)
(require '[buddy.sign.jwt :as jwt])
(def secret-key "your-secret-key-here")
(defn generate-token [user-id]
(jwt/sign {:user-id user-id :exp (+ (System/currentTimeMillis) 3600000)} secret-key))
(defn verify-token [token]
(try
(jwt/unsign token secret-key)
(catch Exception e
{:error "Invalid token"})))
;; Authentication middleware
(defn wrap-authentication [handler]
(fn [request]
(let [token (get-in request [:headers "authorization"])
auth-result (when token (verify-token token))]
(if (:error auth-result)
{:status 401 :body {:error "Unauthorized"}}
(handler (assoc request :user (:data auth-result)))))))
;; Authorization macro
(defmacro require-role [role & body]
(let [user# (:user *request*)]
(if (= (:role user#) ~role)
(do ~@body)
{:status 403 :body {:error "Forbidden"}})))
;; 5. RESTful API with Data Validation
;; Validation library usage
(require '[clojure.spec.alpha :as s])
(s/def ::name string?)
(s/def ::email #(re-matches #".+@.+..+" %))
(s/def ::age int?)
(s/def ::user (s/keys :req-un [::name ::email]
:opt-un [::age]))
(defn validate-request [data spec]
(if (s/valid? spec data)
{:success true :data data}
{:success false :errors (s/explain-data spec data)}))
;; API endpoint with validation
(defn create-user-api [request]
(let [user-data (:body request)
validation (validate-request user-data ::user)]
(if (:success validation)
(try
(let [created-user (create-user! (:data validation))]
{:status 201 :body created-user})
(catch Exception e
{:status 500 :body {:error "Database error"}}))
{:status 400 :body {:errors (:errors validation)}})))
;; 6. Real-time WebSocket Communication
(require '[ring.adapter.jetty :as jetty])
(require '[clojure.data.json :as json])
(def websocket-connections (atom #{}))
(defn websocket-handler [request]
{:status 101
:headers {"Upgrade" "websocket"
"Connection" "Upgrade"}})
(defn broadcast-message! [message]
(doseq [connection @websocket-connections]
(try
(.send connection (json/write-str message))
(catch Exception e
(swap! websocket-connections disj connection)))))
(defn handle-websocket-message [connection message]
(let [parsed (json/read-str message)]
(case (:type parsed)
:chat (broadcast-message!
{:type :chat
:user (:user parsed)
:message (:message parsed)
:timestamp (System/currentTimeMillis)})
:join (swap! websocket-connections conj connection))))
;; 7. Background Jobs and Task Queue
;; Simple task queue using atoms
(def task-queue (atom clojure.lang.PersistentQueue/EMPTY))
(def workers (atom {}))
(defn enqueue-task! [task]
(swap! task-queue conj task))
(defn dequeue-task! []
(first (swap-vals! task-queue pop)))
(defn start-worker! [worker-id]
(future
(loop []
(when-let [task (dequeue-task!)]
(try
(println (str "Worker " worker-id " processing task: " (:type task)))
((:handler task) task)
(catch Exception e
(println (str "Worker " worker-id " error: " (.getMessage e)))))
(recur)))))
(defn stop-worker! [worker-id]
(when-let [worker-future (get @workers worker-id)]
(future-cancel worker-future)
(swap! workers dissoc worker-id)))
;; Example tasks
(defn send-email-task [task]
(Thread/sleep 2000) ; Simulate sending email
(println (str "Email sent to " (:to task))))
(defn process-image-task [task]
(Thread/sleep 5000) ; Simulate image processing
(println (str "Image processed: " (:image-path task))))
;; Enqueue tasks
(enqueue-task! {:type :send-email
:to "[email protected]"
:handler send-email-task})
(enqueue-task! {:type :process-image
:image-path "/path/to/image.jpg"
:handler process-image-task})
;; Start worker threads
(swap! workers assoc :worker1 (start-worker! 1))
(swap! workers assoc :worker2 (start-worker! 2))
;; 8. Configuration Management
;; Configuration loading
(defn load-config [env]
(case env
:development {:port 3000 :db-url "jdbc:h2:mem:dev" :debug true}
:test {:port 3001 :db-url "jdbc:h2:mem:test" :debug false}
:production {:port 80 :db-url "jdbc:postgresql://prod/db" :debug false}
{:port 3000 :db-url "jdbc:h2:mem:default" :debug false}))
(def config (load-config (keyword (or (System/getenv "ENV") "development"))))
;; Environment-specific middleware
(defn wrap-dev-only [handler]
(if (:debug config)
handler
(fn [request] {:status 404 :body "Not found"})))
;; 9. Error Handling and Logging
;; Structured logging
(defn log-event [level message data]
(let [log-entry {:timestamp (System/currentTimeMillis)
:level level
:message message
:data data}]
(println (clojure.data.json/write-str log-entry))
log-entry))
;; Global error handler
(defn wrap-error-handling [handler]
(fn [request]
(try
(handler request)
(catch Exception e
(log-event :error "Unhandled exception"
{:exception (.getMessage e)
:stack-trace (map str (.getStackTrace e))})
{:status 500 :body {:error "Internal server error"}}))))
;; 10. Testing and Development Tools
;; Test data generation
(defn generate-test-user []
{:name (str "Test User " (rand-int 1000))
:email (str "test" (rand-int 1000) "@example.com")
:age (+ 18 (rand-int 50))})
;; Route testing helper
(defn test-route [app-routes request-method uri]
((app-routes {:request-method request-method :uri uri}) {}))
;; Start the server (comment out in production)
;; (jetty/run-jetty app {:port (:port config) :join? false})